package o2o.business.dispatch;


import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.jinyou.utils.common.*;
import com.mongodb.BasicDBObject;
import lombok.extern.slf4j.Slf4j;
import o2o.cache.agent.AgentOrderOverTimeMemory;
import o2o.cache.agent.CityAgentMemory;
import o2o.cache.agent.PostmanAgentRelationMemory;
import o2o.cache.honeycomb.HoneycombMemory;
import o2o.cache.order.OrderInfoMemory;
import o2o.cache.order.postman.PostmanOrderMemoryMan;
import o2o.cache.postman.CityPostmanMemory;
import o2o.cache.postman.PostmanPositionMemory;
import o2o.cache.postman.PostmanShopRelationMemory;
import o2o.cache.shop.ShopMemory;
import o2o.cache.sys.SysConfigDepositMemory;
import o2o.cache.system.SysSettingMemory;
import o2o.cache.user.UserInfoMemory;
import o2o.cache.wallet.UserWalletMemory;
import o2o.dao.PO.agent.CityAgent;
import o2o.dao.PO.agent.OrderOverTimeInfo;
import o2o.dao.PO.common.ResultInfo;
import o2o.dao.PO.common.UserType;
import o2o.dao.PO.order.*;
import o2o.dao.PO.postman.POSTMAN_WORK_STATUS;
import o2o.dao.PO.postman.PostmanPositionInfo;
import o2o.company.model.ShopInfo;
import o2o.dao.PO.sys.SysSetting;
import o2o.dao.PO.user.UserInfo;
import o2o.dao.PO.wallet.UserWallet;
import o2o.postman.model.CityPostman;
import o2o.system.data.SYS_SETTINGS;
import o2o.web.actions.order.OrderMan;
import o2o.web.actions.sys.GrabOrderModeMan;
import org.apache.commons.lang.StringUtils;

import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

// 订单指派
// 1. 获取该范围内所有开工骑手，按距离收获地址最近的排序后
// 2. 遍历上一步获取的所有的骑手，是否有骑手进行中订单是空的
// 3. 如果有，直接指派
// 4. 如果所有骑手都有订单，进入下一步
// 5. 遍历1中得到的骑手，计算每个骑手，最早的订单与当前订单的方向夹角及骑手距离当前订单和最早订单的距离。夹角小于45度的，并且新距离小于最早订单的距离的骑手，记录下来
// 6. 将第5步中所有的骑手，按新距离排序
// 7. 遍历6中得到的骑手，判读骑手进行中是否订单量是否达到了最大值，如果未达到直接指派
// 8. 如果所有骑手都达到了上线，等待下一轮指派

// 距离商家的距离、距离用户距离、夹角、订单量  权重
@Slf4j
public class DispatchPostmanBusinessV2 {
    public static ResultInfo dispatch(String orderNo,
                                      String opUsername) {
        ResultInfo resultInfo = null;
        OrderInfo orderInfo = OrderInfoMemory.getInstance().getOrderInfo(orderNo);
        ShopInfo shopInfo = ShopMemory.getInstance().getShopByUsername(orderInfo.getUsername());
        if (shopInfo == null) {
            shopInfo = ShopMemory.getInstance().getShopById(orderInfo.getShopId());
        }

        Long shopId = orderInfo.getShopId();
        boolean runNewRule = false;
        // 查询订单所属门店
        if (shopInfo != null && StringUtils.isNotEmpty(shopInfo.getSendOrderRule())) {
            // 派单规则 1 系统派单 2 抢单
            String sendOrderRule = shopInfo.getSendOrderRule();
            if ("1".equals(sendOrderRule)) {
                runNewRule = true;
                Long shopRang = 0l;
                resultInfo = dispatchServerV4(orderNo, shopRang, opUsername);
            }
        }
        if (!runNewRule) {
            // 判断是否开启了调度
            if (dispatchModel(orderNo) <= 0) {
                System.out.println("订单号[" + orderNo + "] 代理未开启调度模式");
                return new ResultInfo();
            }
            // 只有1 , 2和3都属于冗余代码
            switch (SYS_SETTINGS.IS_OPEN_AUTO_DISPATCH_ORDER) {
                case ORDER_AUTO_DISPATCH_STYLE.ALL_ORDER: {// 取到所有订单，然后再送到用户
                    Long shopRang = 0l;
                    SysSetting setting = SysSettingMemory.getInstance().getByCode("isOpenAutoDispatchOrder");
                    if (setting != null) {
                        shopRang = JYMathDoubleUtils.toLong(setting.getNote());
                    }
                    resultInfo = dispatchServerV4(orderNo, shopRang, opUsername);
                }
                break;
                case ORDER_AUTO_DISPATCH_STYLE.ONE_ORDER: {// 一单一单送，送完一个用户，再取另外一个用户再送
                    resultInfo = dispatchSeverV2(orderNo, opUsername);
                }
                break;
                case ORDER_AUTO_DISPATCH_STYLE.SHOP_USER: {
                    Long shopRang = 0l;
                    Long userRang = 0l;
                    SysSetting setting = SysSettingMemory.getInstance().getByCode("isOpenAutoDispatchOrder");
                    if (setting != null) {
                        String note = setting.getNote();
                        if (ValidateUtil.isNotNull(note) && note.contains(",")) {
                            String[] rangArr = note.split(",");
                            if (null != rangArr) {
                                for (int i = 0; i < rangArr.length; i++) {
                                    if (0 == i) {
                                        shopRang = JYMathDoubleUtils.toLong(setting.getNote());
                                    } else if (1 == i) {
                                        userRang = JYMathDoubleUtils.toLong(setting.getNote());
                                    }
                                }
                            }
                        } else {
                            shopRang = JYMathDoubleUtils.toLong(setting.getNote());
                            userRang = JYMathDoubleUtils.toLong(setting.getNote());
                        }
                    }
                    resultInfo = dispatchServerV3(orderNo, shopRang, userRang, opUsername);
                }
                break;
            }
        }
        if (null == resultInfo) {
            return new ResultInfo("骑手都无效");
        } else {
            return resultInfo;
        }
    }

    /**
     * 判断调度模式
     *
     * @return
     */
    private static int dispatchModel(String orderNo) {
        if (SYS_SETTINGS.ADMIN_MANAGER_DISPATCH_ORDER_MODE != null && SYS_SETTINGS.ADMIN_MANAGER_DISPATCH_ORDER_MODE > 0) {
            OrderInfo orderInfo = OrderInfoMemory.getInstance().getOrderInfo(orderNo);
            if (orderInfo == null) {
                System.out.println("获取是否启用派单时,获取订单失败~orderNo:" + orderNo);
            } else {
                return GrabOrderModeMan.getDispatchOrderModeByAgentId(orderInfo.getAgentId());
            }
        }
        return SYS_SETTINGS.IS_OPEN_AUTO_DISPATCH_ORDER == null ? 0 : SYS_SETTINGS.IS_OPEN_AUTO_DISPATCH_ORDER;

    }

    // 取了所有单一起送
    private static ResultInfo dispatchServer(String orderNo,
                                             Long shopRang,// 骑手 手里有单话，商家与商家之间的距离
                                             String opUsername) {
//    }
//    public static boolean dispatch(String orderNo,
//                                   String opUsername) {

        StringBuffer errSb = new StringBuffer();

        OrderInfo orderInfo = OrderInfoMemory.getInstance().getOrderInfo(orderNo);
        if (null == orderInfo) {
//            return true;
            System.out.println(DateUtils.getCurrentDateTime() + "  自动派单--订单信息不存在：" + orderNo);
            errSb.append("订单信息不存在:" + orderNo);
            doLog(orderNo, errSb.toString());
            return new ResultInfo();
        }

        // 重复派单问题
        if (ValidateUtil.isNotNull(orderInfo.getPostManUsername())) {
            // 已有骑手不再派单
            System.out.println(DateUtils.getCurrentDateTime() + "  自动派单--已存在骑手：" + orderNo + ",postman:" + orderInfo.getPostManUsername());
//            errSb.append("订单已有骑手:" + orderNo + ",postman:" + orderInfo.getPostManUsername());
//            doLog(orderNo, errSb.toString());
            return new ResultInfo();
        }

        // 只派 配送单
        if (0 != orderInfo.getIsZiQu() - ZI_QU_TYPE.PEI_SONG) {
            return new ResultInfo();
        }


        // 是不是预约单
        if (null != orderInfo.getIsAppointment() && 0 == 1 - orderInfo.getIsAppointment()) {
            // 是不是到了派单时间
            //如果到达预定时间前就可以看到
            //获取系统默认预约提醒时间，可以获取店铺的预约时间  1小时前的订单
            Long nowTime = DateUtils.getCurrTime();//当前时间
            //            Integer noticeTime = 60;// 默认没有设置的话60分钟
            // 获取商圈配置的时间
//            Long agentId = orderInfo.getAgentId();
//            if (ValidateUtil.isID(agentId)) {
//                OrderOverTimeInfo orderOverTimeInfo = AgentOrderOverTimeMemory.getInstance().getAgentOrderOverTimeInfoByAgentId(agentId);
//                if (null != orderOverTimeInfo && ValidateUtil.isAbsInteger(orderOverTimeInfo.getAppointPostmanTime())) {
//                    noticeTime = orderOverTimeInfo.getAppointPostmanTime();
//                }
//            }

            Integer noticeTime = orderInfo.getAgentAppointPostmanTime();
            if (null == noticeTime) {
                // 获取商圈配置的时间
                Long agentId = orderInfo.getAgentId();
                if (ValidateUtil.isID(agentId)) {
                    OrderOverTimeInfo orderOverTimeInfo = AgentOrderOverTimeMemory.getInstance().getAgentOrderOverTimeInfoByAgentId(agentId);
                    if (null != orderOverTimeInfo && ValidateUtil.isAbsInteger(orderOverTimeInfo.getAppointPostmanTime())) {
                        noticeTime = orderOverTimeInfo.getAppointPostmanTime();
                    }
                }
            }
            if (ValidateUtil.isAbsInteger(noticeTime) && noticeTime < 5) {
                Integer postmanOverTime = orderInfo.getAgentPostmanOverTime();// 设置的要求骑手时长(postmanOverTime)
                if (null == postmanOverTime) {
                    postmanOverTime = 0;
                }
                Integer alertPostmanTime = orderInfo.getAlertPostmanTime();//  设置的骑手即将超时提醒时间[骑手接单-确认送达](alertPostmanTime)
                if (null == alertPostmanTime) {
                    alertPostmanTime = 0;
                }
//                noticeTime = postmanOverTime + alertPostmanTime + 20;
                noticeTime = postmanOverTime + alertPostmanTime;
                if (noticeTime <= 0) {
                    // 默认1小时
                    noticeTime = 60;
                } else {
                    noticeTime = noticeTime + 20;
                }
            }
            if (orderInfo.getZiQuTime() - nowTime <= noticeTime * 60 * 1000) {
                //推送给骑手
            } else {
                // 不到时间
                System.out.println(DateUtils.getCurrentDateTime() + "   自动派单--不到时间：" + orderNo + ":" + orderInfo.getZiQuTime());
//                return false;
                errSb.append("预约订单未到派单时间：" + orderNo + ",预约时间：" + orderInfo.getZiQuTime() + "\n");
                doLog(orderNo, errSb.toString());
                return new ResultInfo("预约订单未到派单时间");
            }
        }

        // 订单状态是否满足要求
        if ((ORDER_STATUS.SHOP_SURE == orderInfo.getOrderStatus() && 0 == orderInfo.getIsZiQu())
                || (ORDER_STATUS.PAYED == orderInfo.getOrderStatus() && (null != orderInfo.getOrderType() && (0 == ORDER_TYPE.PAO_TUI - orderInfo.getOrderType() || 0 == ORDER_TYPE.DAI_GOU - orderInfo.getOrderType() || 0 == ORDER_TYPE.BANG_BAN - orderInfo.getOrderType() || 0 == ORDER_TYPE.HUO_YUN - orderInfo.getOrderType())))
                || (0 == ORDER_STATUS.SUBMIT - orderInfo.getOrderStatus() && (null != orderInfo.getOrderType() && 0 == ORDER_TYPE.SERVICE_LOCK - orderInfo.getOrderType()))) {

        } else {
//            return true;
            System.out.println(DateUtils.getCurrentDateTime() + "    自动派单--订单状态不满足要求：" + orderNo + ":" + orderInfo.getOrderStatus());
            errSb.append("订单状态不满足要求：" + orderNo + ",当前状态：" + orderInfo.getOrderStatus() + "\n");
            doLog(orderNo, errSb.toString());
            return new ResultInfo();
        }

        // 订单经纬度是否符合要求
        if (ValidateUtil.isNotLatLng(orderInfo.getLat(), orderInfo.getLng())) {
//            return true;
            System.out.println(DateUtils.getCurrentDateTime() + "  自动派单--订单信息经纬度为空：" + orderInfo.getLat() + "," + orderInfo.getLng());
            errSb.append("订单信息经纬度为空：" + orderNo + "\n");
            doLog(orderNo, errSb.toString());
            return new ResultInfo();
        }
        Integer agentRang = null;
        List<String> pUserList = null;
        Long agentId = null;
        ShopInfo shop = null;
        if (SYS_SETTINGS.POSTMAN_SERVICE_SHOP != null && SYS_SETTINGS.POSTMAN_SERVICE_SHOP == 1
                && ((orderInfo.getOrderType() - ORDER_TYPE.PAO_TUI == 0 && orderInfo.getIsShopPaoTuiOrder() != null && orderInfo.getIsShopPaoTuiOrder() == 1)
                || !ORDER_TYPE.PAOTUI_TYPE_LIST.contains(orderInfo.getOrderType()))) {

            if (orderInfo.getOrderType() != null && orderInfo.getOrderType() - ORDER_TYPE.PAO_TUI == 0 && orderInfo.getIsShopPaoTuiOrder() != null && orderInfo.getIsShopPaoTuiOrder() == 1) {
                // 商家跑腿订单
                shop = ShopMemory.getInstance().getShopByUsername(orderInfo.getUsername());
            } else {
                shop = ShopMemory.getInstance().getShopById(orderInfo.getShopId());
            }
            if (shop == null) {
                System.out.println(DateUtils.getCurrentDateTime() + "  自动派单--店铺信息为空：" + orderInfo.getShopId());
                errSb.append("店铺信息为空：" + orderNo + "\n");
                doLog(orderNo, errSb.toString());
                return new ResultInfo();
            }
            pUserList = PostmanShopRelationMemory.getInstance().listShopPostManListByShopUsername(shop.getOwnUsername());
            if (!ValidateUtil.isAbsList(pUserList)) {
                // 商家没有骑手
//                System.out.println("当前商家没有骑手:" + orderInfo.getOrderNo() + "," + orderInfo.getShopId());
                errSb.append("当前商家没有骑手：" + orderNo + ",商圈id：" + orderInfo.getShopId() + "\n");
                doLog(orderNo, errSb.toString());
                return new ResultInfo("当前商家没有骑手");
            }
            agentRang = SYS_SETTINGS.DELIVERY_RANGE;
            if (ValidateUtil.isNotAbsInteger(agentRang)) {
                agentRang = 5;
            }
        } else {
            // 商家跑腿订单
            shop = ShopMemory.getInstance().getShopByUsername(orderInfo.getUsername());
            if (shop == null) {
                shop = ShopMemory.getInstance().getShopById(orderInfo.getShopId());
            }
            // 门店不为空 且 门店是否开启第三方配送不为空
            if (shop != null && StringUtils.isNotEmpty(shop.getThirdPartyType())) {
                String thirdPartyType = shop.getThirdPartyType();
                if ("1".equals(thirdPartyType)) {
                    // 达到多少公里
                    String thirdPartyCond = shop.getThirdPartyCond();
                    // 第三方配送
                    String thirdParty = shop.getThirdParty();
                    // 计算商家与买家的距离
                    double distance = Geohash.distance(orderInfo.getLat(), orderInfo.getLng(), orderInfo.getShopLat(), orderInfo.getShopLng());
                    // 如果大于, 甩给第三方配送
                    if (distance > Integer.parseInt(thirdPartyCond) * 1000) {
                        switch (thirdParty) {
                            case "DaDa":

                                break;
                        }
                    }
                }
            } else {
                // 获取订单所属商圈
                agentId = orderInfo.getAgentId();
                if (ValidateUtil.isNotID(agentId)) {
                    // todo 不是按商圈的，根据经纬度处理
                    System.out.println(DateUtils.getCurrentDateTime() + "  自动派单--商圈id为空：" + orderNo);
//            return true;
                    errSb.append("商圈id为空：" + orderNo + "\n");
                    doLog(orderNo, errSb.toString());
                    return new ResultInfo();
                }
                CityAgent agentInfo = CityAgentMemory.getInstance().getById(agentId);
                if (null == agentInfo) {
//            return true;
                    System.out.println(DateUtils.getCurrentDateTime() + "  自动派单--商圈信息不存在：" + orderNo);
                    errSb.append("商圈信息不存在：" + orderNo + ",商圈id：" + agentId + "\n");
                    doLog(orderNo, errSb.toString());
                    return new ResultInfo();
                }
                // 商圈最大距离
                agentRang = agentInfo.getRang();
                if (ValidateUtil.isNotAbsInteger(agentRang)) {
                    agentRang = SYS_SETTINGS.DELIVERY_RANGE;
                    if (ValidateUtil.isNotAbsInteger(agentRang)) {
                        agentRang = 5;
                    }
                }
                // 获取该商圈所有骑手
                pUserList = PostmanAgentRelationMemory.getInstance().listOfAgentId(agentId);
                if (!ValidateUtil.isAbsList(pUserList)) {
                    // 该商圈没有骑手
                    System.out.println("该商圈没有骑手:" + orderInfo.getOrderNo() + "," + orderInfo.getAgentId());
//            return false;
                    errSb.append("该商圈没有骑手：" + orderNo + ",商圈id：" + agentId + "\n");
                    doLog(orderNo, errSb.toString());
                    return new ResultInfo("该商圈没有骑手");
                }
            }
        }

        // 符合条件骑手
        List<DispatchInfo> disList = new ArrayList<>();
        // 无符合条件骑手时的备用骑手
        List<DispatchInfo> usList = new ArrayList<>();
        // 遍历骑手
        for (int i = 0; i < pUserList.size(); i++) {
            String username = pUserList.get(i);
            if (ValidateUtil.isNull(username)) {
                continue;
            }

            // 获取骑手信息
            CityPostman postman = CityPostmanMemory.getInstance().getPostman(username);
            if (null == postman) {
                continue;
            }

            // 骑手的位置信息
            PostmanPositionInfo positionInfo = PostmanPositionMemory.getInstance().get(postman.getId());
            if (null == positionInfo) {
                System.out.println(DateUtils.getCurrentDateTime() + "  自动派单--骑手位置信息不存在：" + orderNo + "；username:" + username + ";postmanId:" + postman.getId());
                errSb.append(username + ",骑手位置信息不存在：" + orderNo + "\n");
                continue;
            }

            // 经纬度是否有效
            if (ValidateUtil.isNotLatLng(positionInfo.getLat(), positionInfo.getLng())) {
                System.out.println(DateUtils.getCurrentDateTime() + "  自动派单--骑手位置信息不完整：" + orderNo + "；username:" + username);
                errSb.append(username + ",骑手位置信息不完整：" + orderNo + "\n");
                continue;
            }

            // 验证骑手的基本信息
            ResultInfo resultInfo = isUsefulPostmanBase(postman, agentId, orderNo);
            if (null == resultInfo) {
                // 失败
                System.out.println(DateUtils.getCurrentDateTime() + "  自动派单--无效骑手：" + orderNo + "；username:" + username);
                errSb.append(username + ",无效骑手:" + orderNo);
                continue;
            } else {
                if (!resultInfo.isSuccess()) {
                    System.out.println(DateUtils.getCurrentDateTime() + "  自动派单--" + resultInfo.getError() + "：" + orderNo + "；username:" + username);
//                    errSb.append("---begin----" + username + ",无效骑手:" + orderNo + "-------\n");
                    errSb.append(resultInfo.getError() + "\n");
//                    errSb.append("---end----" + username + ",无效骑手:" + orderNo + "-------\n");
                    continue;
                }
            }

            DispatchInfo dispatchInfo = new DispatchInfo();
            // 骑手离订单的距离(米)
            double distance = 0;
            if (ValidateUtil.isLatLng(orderInfo.getShopLat(), orderInfo.getShopLng())) {
                distance = Geohash.distance(positionInfo.getLat(), positionInfo.getLng(), orderInfo.getShopLat(), orderInfo.getShopLng());
            } else {
                distance = Geohash.distance(positionInfo.getLat(), positionInfo.getLng(), orderInfo.getLat(), orderInfo.getLng());
            }

            // 距离是否超出商圈范围
            if (JYMathDoubleUtils.sub(distance, agentRang * 1000) > 0) {
                System.out.println(DateUtils.getCurrentDateTime() + "  自动派单--距离超出商圈范围：" + orderNo + "；" + distance);
                errSb.append(username + ",距离骑手，超出范围：" + orderNo + ",实际距离：" + (JYMathDoubleUtils.div(distance, 1000, 2)) + ",商圈范围：" + agentRang + "\n");
                continue;
            }
            dispatchInfo.setPostmanInfo(postman);
            dispatchInfo.setDistance(distance);

            // 备用骑手
            usList.add(dispatchInfo);

            // 获取骑手进行中的一个订单
            List<OrderInfo> orderList = PostmanOrderMemoryMan.listOfPostmanIng(postman.getUsername(), 0l, 1);
            if (ValidateUtil.isAbsList(orderList)) {
                OrderInfo postmanOrder = orderList.get(0);
                if (null != postmanOrder && ValidateUtil.isLatLng(postmanOrder.getLat(), postmanOrder.getLng())) {
                    // 获取骑手最后订单与新订单夹角
                    double angle = AngleUtils.getDegree(positionInfo.getLat(), positionInfo.getLng(),
                            postmanOrder.getLat(), postmanOrder.getLng(),
                            orderInfo.getLat(), orderInfo.getLng());

                    // todo 夹角大于45度
                    if (angle > 45) {
//                        System.out.println("夹角大于45：" + orderNo + "," + angle);
                        System.out.println(DateUtils.getCurrentDateTime() + "  自动派单--夹角大于45：" + orderNo + "；角度：" + angle + ";骑手：" + postman.getUsername());
                        errSb.append(username + ",距离骑手，超出范围：" + orderNo + ",夹角大于45：" + angle + "\n");
                        continue;
                    }
                    dispatchInfo.setAngle(angle);

                    // 手里有单话，商家与商家之间的距离
                    if (ValidateUtil.isAbsLong(shopRang) && shopRang > 0 && ValidateUtil.isLatLng(orderInfo.getShopLat(), orderInfo.getShopLng())) {
                        // 商家与商家之间的距离(米)
                        double shopDis = Geohash.distance(orderInfo.getLat(), orderInfo.getLng(), orderInfo.getShopLat(), orderInfo.getShopLng());
                        if (shopRang - shopDis < 0) {
                            System.out.println(DateUtils.getCurrentDateTime() + "  自动派单--商家与商家距离超过" + shopRang + "米：" + orderNo + "；骑手：" + postman.getUsername());
                            errSb.append(username + ",距离骑手，商家与商家距离超过" + shopRang + "米：" + orderNo + ",距离：" + shopDis + "米\n");
                            continue;
                        }
                    }

                }
            }


            disList.add(dispatchInfo);
        }

        if (!ValidateUtil.isAbsList(disList)) {
            // 无符合条件骑手，并且只有一个备用骑手时，直接派个备用骑手（因为有商圈只有一个骑手）
            if (ValidateUtil.isAbsList(usList) && usList.size() == 1) {
                if (null != usList.get(0) && null != usList.get(0).getPostmanInfo()) {
                    OrderMan.setOrderPostman(orderInfo.getOrderNo(), usList.get(0).getPostmanInfo(), opUsername);
//                    return true;
                    return new ResultInfo();
                }
            }
//            return false;
            System.out.println(DateUtils.getCurrentDateTime() + "  自动派单--没有可选择的骑手：" + orderNo + "\n");
            errSb.append("没有可选择的骑手：" + orderNo + "\n");
            doLog(orderNo, errSb.toString());
            return new ResultInfo("没有可选择的骑手" + "\n");
        }
        // 将骑手按距离最近的最前面排序
        JYListSort.sort(disList, "distance");

        // 骑手最多可接单数量
        int postmanMaxOrderCount = 10;
        boolean isAgentSettings = false;// 是否使用商圈的设置
        if (ValidateUtil.isID(agentId)) {
            OrderOverTimeInfo overTimeInfo = AgentOrderOverTimeMemory.getInstance().getAgentOrderOverTimeInfoByAgentId(agentId);
            if (null != overTimeInfo) {
                postmanMaxOrderCount = overTimeInfo.getPostmanMaxOrderNum();
                isAgentSettings = true;
            }
        }
        if (!isAgentSettings && null != SYS_SETTINGS.POSTMAN_MAX_ORDER_NUM && SYS_SETTINGS.POSTMAN_MAX_ORDER_NUM > 0) {
            postmanMaxOrderCount = SYS_SETTINGS.POSTMAN_MAX_ORDER_NUM;
        }

        // 遍历骑手列表
        for (int i = 0; i < disList.size(); i++) {
            DispatchInfo dispatchInfo = disList.get(i);
            if (null == dispatchInfo) {
                continue;
            }
            CityPostman postman = dispatchInfo.getPostmanInfo();
            if (null == postman) {
                continue;
            }
            if (ValidateUtil.isNull(postman.getUsername())) {
                continue;
            }
            // 获取骑手订单量
            Integer orderCount = PostmanOrderMemoryMan.getPostmanIngOrderCount(postman.getUsername());
            if (null == orderCount) {
                orderCount = 0;
            }
            if (0 == orderCount) {
                // 该骑手没有订单
                System.out.println(DateUtils.getCurrentDateTime() + "  自动派单--该骑手没有订单，派给他：" + orderNo + ",orderCount: " + orderCount + "\n");
                // 所需要的骑手
                OrderMan.setOrderPostman(orderInfo.getOrderNo(), postman, opUsername);
                // 结束
//                return true;
                return new ResultInfo();
            }

            disList.get(i).setOrderCount(orderCount);
        }

        // 遍历骑手列表
        for (int i = 0; i < disList.size(); i++) {
            DispatchInfo dispatchInfo = disList.get(i);
            if (null == dispatchInfo) {
                continue;
            }
            CityPostman postman = dispatchInfo.getPostmanInfo();
            if (null == postman) {
                continue;
            }
            if (ValidateUtil.isNull(postman.getUsername())) {
                continue;
            }
            // 获取骑手订单量
            Integer orderCount = dispatchInfo.getOrderCount();

            // 骑手可接单量
            if (postmanMaxOrderCount > 0 && orderCount >= postmanMaxOrderCount) {
                System.out.println("超出骑手可接单量：" + orderInfo.getOrderNo() + "," + postmanMaxOrderCount + "," + orderCount);
                errSb.append(postman.getUsername() + ",超出骑手可接单量：" + orderNo + ",可接单数量：" + postmanMaxOrderCount + ",实际数量" + orderCount + "\n");
                continue;
            } else {
                // 分配
                OrderMan.setOrderPostman(orderInfo.getOrderNo(), postman, opUsername);
//                return true;
                return new ResultInfo();
            }
        }

        // 无符合条件骑手，并且只有一个备用骑手时，直接派个备用骑手（因为有商圈只有一个骑手）
        if (ValidateUtil.isAbsList(usList) && usList.size() == 1) {
            System.out.println("有一个备用骑手：" + orderNo);
            if (null != usList.get(0) && null != usList.get(0).getPostmanInfo()) {
                OrderMan.setOrderPostman(orderInfo.getOrderNo(), usList.get(0).getPostmanInfo(), opUsername);
//                return true;
                return new ResultInfo();
            } else {
                System.out.println("一个备用骑手无效：" + orderNo);
                errSb.append("一个备用骑手无效：" + orderNo + "\n");
            }
        }

        System.out.println(DateUtils.getCurrentDateTime() + "  自动派单--没有可选择的骑手：" + orderNo);
        errSb.append("没有可选择的骑手：" + orderNo + "\n");
        doLog(orderNo, errSb.toString());
        return new ResultInfo("骑手都无效");
    }

    /**
     * 一单一单的送
     * 每一单都是先从商家取货，然后送到用户，再去另外一个商家。所以是否要派单，主要看最后一单的收货地址和商家的位置最小的
     */
    private static ResultInfo dispatchSeverV2(String orderNo,
                                              String opUsername) {
//    }
//    public static boolean dispatch(String orderNo,
//                                   String opUsername) {

        StringBuffer errSb = new StringBuffer();

        OrderInfo orderInfo = OrderInfoMemory.getInstance().getOrderInfo(orderNo);
        if (null == orderInfo) {
//            return true;
            System.out.println(DateUtils.getCurrentDateTime() + "  自动派单--订单信息不存在：" + orderNo);
            errSb.append("订单信息不存在:" + orderNo);
            doLog(orderNo, errSb.toString());
            return new ResultInfo();
        }

        // 重复派单问题
        if (ValidateUtil.isNotNull(orderInfo.getPostManUsername())) {
            // 已有骑手不再派单
            System.out.println(DateUtils.getCurrentDateTime() + "  自动派单--已存在骑手：" + orderNo + ",postman:" + orderInfo.getPostManUsername());
//            errSb.append("订单已有骑手:" + orderNo + ",postman:" + orderInfo.getPostManUsername());
//            doLog(orderNo, errSb.toString());
            return new ResultInfo();
        }

        // 只派 配送单
        if (0 != orderInfo.getIsZiQu() - ZI_QU_TYPE.PEI_SONG) {
            return new ResultInfo();
        }


        // 是不是预约单
        if (null != orderInfo.getIsAppointment() && 0 == 1 - orderInfo.getIsAppointment()) {
            // 是不是到了派单时间
            //如果到达预定时间前就可以看到
            //获取系统默认预约提醒时间，可以获取店铺的预约时间  1小时前的订单
            Long nowTime = DateUtils.getCurrTime();//当前时间
            //            Integer noticeTime = 60;// 默认没有设置的话60分钟
            // 获取商圈配置的时间
//            Long agentId = orderInfo.getAgentId();
//            if (ValidateUtil.isID(agentId)) {
//                OrderOverTimeInfo orderOverTimeInfo = AgentOrderOverTimeMemory.getInstance().getAgentOrderOverTimeInfoByAgentId(agentId);
//                if (null != orderOverTimeInfo && ValidateUtil.isAbsInteger(orderOverTimeInfo.getAppointPostmanTime())) {
//                    noticeTime = orderOverTimeInfo.getAppointPostmanTime();
//                }
//            }

            Integer noticeTime = orderInfo.getAgentAppointPostmanTime();
            if (null == noticeTime) {
                // 获取商圈配置的时间
                Long agentId = orderInfo.getAgentId();
                if (ValidateUtil.isID(agentId)) {
                    OrderOverTimeInfo orderOverTimeInfo = AgentOrderOverTimeMemory.getInstance().getAgentOrderOverTimeInfoByAgentId(agentId);
                    if (null != orderOverTimeInfo && ValidateUtil.isAbsInteger(orderOverTimeInfo.getAppointPostmanTime())) {
                        noticeTime = orderOverTimeInfo.getAppointPostmanTime();
                    }
                }
            }
            if (ValidateUtil.isAbsInteger(noticeTime) && noticeTime < 5) {
                Integer postmanOverTime = orderInfo.getAgentPostmanOverTime();// 设置的要求骑手时长(postmanOverTime)
                if (null == postmanOverTime) {
                    postmanOverTime = 0;
                }
                Integer alertPostmanTime = orderInfo.getAlertPostmanTime();//  设置的骑手即将超时提醒时间[骑手接单-确认送达](alertPostmanTime)
                if (null == alertPostmanTime) {
                    alertPostmanTime = 0;
                }
//                noticeTime = postmanOverTime + alertPostmanTime + 20;
                noticeTime = postmanOverTime + alertPostmanTime;
                if (noticeTime <= 0) {
                    // 默认1小时
                    noticeTime = 60;
                } else {
                    noticeTime = noticeTime + 20;
                }
            }
            if (orderInfo.getZiQuTime() - nowTime <= noticeTime * 60 * 1000) {
                //推送给骑手
            } else {
                // 不到时间
                System.out.println(DateUtils.getCurrentDateTime() + "   自动派单--不到时间：" + orderNo + ":" + orderInfo.getZiQuTime());
//                return false;
                errSb.append("预约订单未到派单时间：" + orderNo + ",预约时间：" + orderInfo.getZiQuTime() + "\n");
                doLog(orderNo, errSb.toString());
                return new ResultInfo("预约订单未到派单时间");
            }
        }

        // 订单状态是否满足要求
        if ((ORDER_STATUS.SHOP_SURE == orderInfo.getOrderStatus() && 0 == orderInfo.getIsZiQu())
                || (ORDER_STATUS.PAYED == orderInfo.getOrderStatus() && (null != orderInfo.getOrderType() && (0 == ORDER_TYPE.PAO_TUI - orderInfo.getOrderType() || 0 == ORDER_TYPE.DAI_GOU - orderInfo.getOrderType() || 0 == ORDER_TYPE.BANG_BAN - orderInfo.getOrderType() || 0 == ORDER_TYPE.HUO_YUN - orderInfo.getOrderType())))
                || (0 == ORDER_STATUS.SUBMIT - orderInfo.getOrderStatus() && (null != orderInfo.getOrderType() && 0 == ORDER_TYPE.SERVICE_LOCK - orderInfo.getOrderType()))) {

        } else {
//            return true;
            System.out.println(DateUtils.getCurrentDateTime() + "    自动派单--订单状态不满足要求：" + orderNo + ":" + orderInfo.getOrderStatus());
            errSb.append("订单状态不满足要求：" + orderNo + ",当前状态：" + orderInfo.getOrderStatus() + "\n");
            doLog(orderNo, errSb.toString());
            return new ResultInfo();
        }

        // 订单经纬度是否符合要求
        if (ValidateUtil.isNotLatLng(orderInfo.getLat(), orderInfo.getLng())) {
//            return true;
            System.out.println(DateUtils.getCurrentDateTime() + "  自动派单--订单信息经纬度为空：" + orderInfo.getLat() + "," + orderInfo.getLng());
            errSb.append("订单信息经纬度为空：" + orderNo + "\n");
            doLog(orderNo, errSb.toString());
            return new ResultInfo();
        }
        Long agentId = null;
        Integer agentRang = null;
        List<String> pUserList = null;
        if (SYS_SETTINGS.POSTMAN_SERVICE_SHOP != null && SYS_SETTINGS.POSTMAN_SERVICE_SHOP == 1
                && ((orderInfo.getOrderType() - ORDER_TYPE.PAO_TUI == 0 && orderInfo.getIsShopPaoTuiOrder() != null && orderInfo.getIsShopPaoTuiOrder() == 1)
                || !ORDER_TYPE.PAOTUI_TYPE_LIST.contains(orderInfo.getOrderType()))) {
            ShopInfo shop = null;
            if (orderInfo.getOrderType() != null && orderInfo.getOrderType() - ORDER_TYPE.PAO_TUI == 0 && orderInfo.getIsShopPaoTuiOrder() != null && orderInfo.getIsShopPaoTuiOrder() == 1) {
                // 商家跑腿订单
                shop = ShopMemory.getInstance().getShopByUsername(orderInfo.getUsername());
            } else {
                shop = ShopMemory.getInstance().getShopById(orderInfo.getShopId());
            }
            if (shop == null) {
                System.out.println(DateUtils.getCurrentDateTime() + "  自动派单--店铺信息为空：" + orderInfo.getShopId());
                errSb.append("店铺信息为空：" + orderNo + "\n");
                doLog(orderNo, errSb.toString());
                return new ResultInfo();
            }
            pUserList = PostmanShopRelationMemory.getInstance().listShopPostManListByShopUsername(shop.getOwnUsername());
            if (!ValidateUtil.isAbsList(pUserList)) {
                // 商家没有骑手
//                System.out.println("当前商家没有骑手:" + orderInfo.getOrderNo() + "," + orderInfo.getShopId());
                errSb.append("当前商家没有骑手：" + orderNo + ",商圈id：" + orderInfo.getShopId() + "\n");
                doLog(orderNo, errSb.toString());
                return new ResultInfo("当前商家没有骑手");
            }
            agentRang = SYS_SETTINGS.DELIVERY_RANGE;
            if (ValidateUtil.isNotAbsInteger(agentRang)) {
                agentRang = 5;
            }
        } else {
            // 获取订单所属商圈
            agentId = orderInfo.getAgentId();
            if (ValidateUtil.isNotID(agentId)) {
                // todo 不是按商圈的，根据经纬度处理
                System.out.println(DateUtils.getCurrentDateTime() + "  自动派单--商圈id为空：" + orderNo);
//            return true;
                errSb.append("商圈id为空：" + orderNo + "\n");
                doLog(orderNo, errSb.toString());
                return new ResultInfo();
            }

            CityAgent agentInfo = CityAgentMemory.getInstance().getById(agentId);
            if (null == agentInfo) {
//            return true;
                System.out.println(DateUtils.getCurrentDateTime() + "  自动派单--商圈信息不存在：" + orderNo);
                errSb.append("商圈信息不存在：" + orderNo + ",商圈id：" + agentId + "\n");
                doLog(orderNo, errSb.toString());
                return new ResultInfo();
            }
            // 商圈最大距离
            agentRang = agentInfo.getRang();
            if (ValidateUtil.isNotAbsInteger(agentRang)) {
                agentRang = SYS_SETTINGS.DELIVERY_RANGE;
                if (ValidateUtil.isNotAbsInteger(agentRang)) {
                    agentRang = 5;
                }
            }
            // 获取该商圈所有骑手
            pUserList = PostmanAgentRelationMemory.getInstance().listOfAgentId(agentId);
            if (!ValidateUtil.isAbsList(pUserList)) {
                // 该商圈没有骑手
                System.out.println("该商圈没有骑手:" + orderInfo.getOrderNo() + "," + orderInfo.getAgentId());
//            return false;
                errSb.append("该商圈没有骑手：" + orderNo + ",商圈id：" + agentId + "\n");
                doLog(orderNo, errSb.toString());
                return new ResultInfo("该商圈没有骑手");
            }
        }
        // 符合条件骑手
        List<DispatchInfo> disList = new ArrayList<>();
        // 无符合条件骑手时的备用骑手
        List<DispatchInfo> usList = new ArrayList<>();
        // 遍历骑手
        for (int i = 0; i < pUserList.size(); i++) {
            String username = pUserList.get(i);
            if (ValidateUtil.isNull(username)) {
                continue;
            }

            // 获取骑手信息
            CityPostman postman = CityPostmanMemory.getInstance().getPostman(username);
            if (null == postman) {
                continue;
            }

            // 骑手的位置信息
            PostmanPositionInfo positionInfo = PostmanPositionMemory.getInstance().get(postman.getId());
            if (null == positionInfo) {
                System.out.println(DateUtils.getCurrentDateTime() + "  自动派单--骑手位置信息不存在：" + orderNo + "；username:" + username + ";postmanId:" + postman.getId());
                errSb.append(username + ",骑手位置信息不存在：" + orderNo + "\n");
                continue;
            }

            // 经纬度是否有效
            if (ValidateUtil.isNotLatLng(positionInfo.getLat(), positionInfo.getLng())) {
                System.out.println(DateUtils.getCurrentDateTime() + "  自动派单--骑手位置信息不完整：" + orderNo + "；username:" + username);
                errSb.append(username + ",骑手位置信息不完整：" + orderNo + "\n");
                continue;
            }

            // 验证骑手的基本信息
            ResultInfo resultInfo = isUsefulPostmanBase(postman, agentId, orderNo);
            if (null == resultInfo) {
                // 失败
                System.out.println(DateUtils.getCurrentDateTime() + "  自动派单--无效骑手：" + orderNo + "；username:" + username);
                errSb.append(username + ",无效骑手:" + orderNo);
                continue;
            } else {
                if (!resultInfo.isSuccess()) {
                    System.out.println(DateUtils.getCurrentDateTime() + "  自动派单--" + resultInfo.getError() + "：" + orderNo + "；username:" + username);
//                    errSb.append("---begin----" + username + ",无效骑手:" + orderNo + "-------\n");
                    errSb.append(resultInfo.getError() + "\n");
//                    errSb.append("---end----" + username + ",无效骑手:" + orderNo + "-------\n");
                    continue;
                }
            }

            DispatchInfo dispatchInfo = new DispatchInfo();
            // 骑手离订单的距离(米)
            double distanceUser = Geohash.distance(positionInfo.getLat(), positionInfo.getLng(), orderInfo.getLat(), orderInfo.getLng());
            // 距离是否超出商圈范围
            if (JYMathDoubleUtils.sub(distanceUser, agentRang * 1000) > 0) {
                System.out.println(DateUtils.getCurrentDateTime() + "  自动派单--距离超出商圈范围：" + orderNo + "；" + distanceUser);
                errSb.append(username + ",距离骑手，超出范围：" + orderNo + ",实际距离：" + (JYMathDoubleUtils.div(distanceUser, 1000, 2)) + ",商圈范围：" + agentRang + "\n");
                continue;
            }
            dispatchInfo.setPostmanInfo(postman);


            // 备用骑手
            usList.add(dispatchInfo);

            // 获取骑手最后一单的距离
            List<OrderInfo> orderList = PostmanOrderMemoryMan.listOfPostmanIng(postman.getUsername(), 0l, 1);
            if (ValidateUtil.isAbsList(orderList)) {
                OrderInfo postmanOrder = orderList.get(0);
                if (null != postmanOrder && ValidateUtil.isLatLng(postmanOrder.getLat(), postmanOrder.getLng())) {
//                    // 获取骑手最后订单与新订单夹角
//                    double angle = AngleUtils.getSubAngle(positionInfo.getLat(), positionInfo.getLng(),
//                            postmanOrder.getLat(), postmanOrder.getLng(),
//                            orderInfo.getLat(), orderInfo.getLng());
//
//                    // todo 夹角大于45度
//                    if (angle > 45) {
////                        System.out.println("夹角大于45：" + orderNo + "," + angle);
//                        System.out.println(DateUtils.getCurrentDateTime() + "  自动派单--夹角大于45：" + orderNo + "；角度：" + angle + ";骑手：" + postman.getUsername());
//                        errSb.append(username + ",距离骑手，超出范围：" + orderNo + ",夹角大于45：" + angle + "\n");
//                        continue;
//                    }
//                    dispatchInfo.setAngle(angle);
                    // 【最后一单距离商家的距离】
                    double distance = Geohash.distance(postmanOrder.getLat(), postmanOrder.getLng(), orderInfo.getShopLat(), orderInfo.getShopLng());
                    dispatchInfo.setDistance(distance);
                } else {
                    // 【骑手距离商家的距离】
                    double distance = Geohash.distance(positionInfo.getLat(), positionInfo.getLng(), orderInfo.getShopLat(), orderInfo.getShopLng());
                    dispatchInfo.setDistance(distance);
                }
            } else {
                // 【骑手距离商家的距离】
                double distance = Geohash.distance(positionInfo.getLat(), positionInfo.getLng(), orderInfo.getShopLat(), orderInfo.getShopLng());
                dispatchInfo.setDistance(distance);
            }


            disList.add(dispatchInfo);
        }

        if (!ValidateUtil.isAbsList(disList)) {
            // 无符合条件骑手，并且只有一个备用骑手时，直接派个备用骑手（因为有商圈只有一个骑手）
            if (ValidateUtil.isAbsList(usList) && usList.size() == 1) {
                if (null != usList.get(0) && null != usList.get(0).getPostmanInfo()) {
                    OrderMan.setOrderPostman(orderInfo.getOrderNo(), usList.get(0).getPostmanInfo(), opUsername);
//                    return true;
                    return new ResultInfo();
                }
            }
//            return false;
            System.out.println(DateUtils.getCurrentDateTime() + "  自动派单--没有可选择的骑手：" + orderNo + "\n");
            errSb.append("没有可选择的骑手：" + orderNo + "\n");
            doLog(orderNo, errSb.toString());
            return new ResultInfo("没有可选择的骑手" + "\n");
        }
        // 将骑手按距离最近的最前面排序
        JYListSort.sort(disList, "distance");

        // 骑手最多可接单数量
        int postmanMaxOrderCount = 10;
        boolean isAgentSettings = false;// 是否使用商圈的设置
        if (ValidateUtil.isID(agentId)) {
            OrderOverTimeInfo overTimeInfo = AgentOrderOverTimeMemory.getInstance().getAgentOrderOverTimeInfoByAgentId(agentId);
            if (null != overTimeInfo) {
                postmanMaxOrderCount = overTimeInfo.getPostmanMaxOrderNum();
                isAgentSettings = true;
            }
        }
        if (!isAgentSettings && null != SYS_SETTINGS.POSTMAN_MAX_ORDER_NUM && SYS_SETTINGS.POSTMAN_MAX_ORDER_NUM > 0) {
            postmanMaxOrderCount = SYS_SETTINGS.POSTMAN_MAX_ORDER_NUM;
        }

//        Double rate = null;
//        SysSetting sysSetting = SysSettingMemory.getInstance().getByCode("isOpenAutoDispatchOrder");// 是否开启自动派单功能  0不开启，1开启
//        if (null != sysSetting) {
//            String note = sysSetting.getNote();// 要加的距离
//            if (ValidateUtil.isNotNull(note) && !"null".equals(sysSetting.getNote()) && !"undefind".equals(sysSetting.getNote())) {
//                rate = Double.parseDouble(note);
//            }
//        }
        // 遍历骑手列表(有空单则直接指派)
        for (int i = 0; i < disList.size(); i++) {
            DispatchInfo dispatchInfo = disList.get(i);
            if (null == dispatchInfo) {
                continue;
            }
            CityPostman postman = dispatchInfo.getPostmanInfo();
            if (null == postman) {
                continue;
            }
            if (ValidateUtil.isNull(postman.getUsername())) {
                continue;
            }

            // 获取骑手订单量
            Integer orderCount = PostmanOrderMemoryMan.getPostmanIngOrderCount(postman.getUsername());
            if (null == orderCount) {
                orderCount = 0;
            }
            if (0 == orderCount) {
                // 该骑手没有订单
                System.out.println(DateUtils.getCurrentDateTime() + "  自动派单--该骑手没有订单，派给他：" + orderNo + ",orderCount: " + orderCount + "\n");
                // 所需要的骑手
                OrderMan.setOrderPostman(orderInfo.getOrderNo(), postman, opUsername);
                // 结束
                return new ResultInfo();
            }
            disList.get(i).setOrderCount(orderCount);

//            // 根据单量加权，如果单量比较少，有限派单
//            if (ValidateUtil.isAbsDouble(rate)) {
//                Double dist = JYMathDoubleUtils.add(dispatchInfo.getDistance(), JYMathDoubleUtils.mul(rate, dispatchInfo.getDistance()));
//                disList.get(i).setDistance(dist);
//            }
        }

//        if (ValidateUtil.isAbsDouble(rate)) {
//            // 重新根据权重排序
//            JYListSort.sort(disList, "distance");
//        }
        // 都有单，派距离近的骑手
        for (int i = 0; i < disList.size(); i++) {
            DispatchInfo dispatchInfo = disList.get(i);
            if (null == dispatchInfo) {
                continue;
            }
            CityPostman postman = dispatchInfo.getPostmanInfo();
            if (null == postman) {
                continue;
            }
            if (ValidateUtil.isNull(postman.getUsername())) {
                continue;
            }
            Integer orderCount = disList.get(i).getOrderCount();
            if (postmanMaxOrderCount > 0 && orderCount >= postmanMaxOrderCount) {
                System.out.println("超出骑手可接单量：" + orderInfo.getOrderNo() + "," + postmanMaxOrderCount + "," + orderCount);
                errSb.append(postman.getUsername() + ",超出骑手可接单量：" + orderNo + ",可接单数量：" + postmanMaxOrderCount + ",实际数量" + orderCount + "\n");
                continue;
            } else {
                // 分配
                OrderMan.setOrderPostman(orderInfo.getOrderNo(), postman, opUsername);
                return new ResultInfo();
            }
        }


        // 无符合条件骑手，并且只有一个备用骑手时，直接派个备用骑手（因为有商圈只有一个骑手）
        if (ValidateUtil.isAbsList(usList) && usList.size() == 1) {
            System.out.println("有一个备用骑手：" + orderNo);
            if (null != usList.get(0) && null != usList.get(0).getPostmanInfo()) {
                OrderMan.setOrderPostman(orderInfo.getOrderNo(), usList.get(0).getPostmanInfo(), opUsername);
//                return true;
                return new ResultInfo();
            } else {
                System.out.println("一个备用骑手无效：" + orderNo);
                errSb.append("一个备用骑手无效：" + orderNo + "\n");
            }
        }

        System.out.println(DateUtils.getCurrentDateTime() + "  自动派单--没有可选择的骑手：" + orderNo);
        errSb.append("没有可选择的骑手：" + orderNo + "\n");
        doLog(orderNo, errSb.toString());
        return new ResultInfo("骑手都无效");
    }


    // 取了所有单一起送
    private static ResultInfo dispatchServerV3(String orderNo,
                                               Long shopRang,// 骑手 手里有单话，商家与商家之间的距离
                                               Long userRang,// 骑手 手里有单话，用户地址与用户地址之间的距离
                                               String opUsername) {
//    }
//    public static boolean dispatch(String orderNo,
//                                   String opUsername) {

        StringBuffer errSb = new StringBuffer();

        OrderInfo orderInfo = OrderInfoMemory.getInstance().getOrderInfo(orderNo);
        if (null == orderInfo) {
//            return true;
            System.out.println(DateUtils.getCurrentDateTime() + "  自动派单--订单信息不存在：" + orderNo);
            errSb.append("订单信息不存在:" + orderNo);
            doLog(orderNo, errSb.toString());
            return new ResultInfo();
        }

        // 重复派单问题
        if (ValidateUtil.isNotNull(orderInfo.getPostManUsername())) {
            // 已有骑手不再派单
            System.out.println(DateUtils.getCurrentDateTime() + "  自动派单--已存在骑手：" + orderNo + ",postman:" + orderInfo.getPostManUsername());
//            errSb.append("订单已有骑手:" + orderNo + ",postman:" + orderInfo.getPostManUsername());
//            doLog(orderNo, errSb.toString());
            return new ResultInfo();
        }

        // 只派 配送单
        if (0 != orderInfo.getIsZiQu() - ZI_QU_TYPE.PEI_SONG) {
            return new ResultInfo();
        }


        // 是不是预约单
        if (null != orderInfo.getIsAppointment() && 0 == 1 - orderInfo.getIsAppointment()) {
            // 是不是到了派单时间
            //如果到达预定时间前就可以看到
            //获取系统默认预约提醒时间，可以获取店铺的预约时间  1小时前的订单
            Long nowTime = DateUtils.getCurrTime();//当前时间
            //            Integer noticeTime = 60;// 默认没有设置的话60分钟
            // 获取商圈配置的时间
//            Long agentId = orderInfo.getAgentId();
//            if (ValidateUtil.isID(agentId)) {
//                OrderOverTimeInfo orderOverTimeInfo = AgentOrderOverTimeMemory.getInstance().getAgentOrderOverTimeInfoByAgentId(agentId);
//                if (null != orderOverTimeInfo && ValidateUtil.isAbsInteger(orderOverTimeInfo.getAppointPostmanTime())) {
//                    noticeTime = orderOverTimeInfo.getAppointPostmanTime();
//                }
//            }

            Integer noticeTime = orderInfo.getAgentAppointPostmanTime();
            if (null == noticeTime) {
                // 获取商圈配置的时间
                Long agentId = orderInfo.getAgentId();
                if (ValidateUtil.isID(agentId)) {
                    OrderOverTimeInfo orderOverTimeInfo = AgentOrderOverTimeMemory.getInstance().getAgentOrderOverTimeInfoByAgentId(agentId);
                    if (null != orderOverTimeInfo && ValidateUtil.isAbsInteger(orderOverTimeInfo.getAppointPostmanTime())) {
                        noticeTime = orderOverTimeInfo.getAppointPostmanTime();
                    }
                }
            }
            if (ValidateUtil.isAbsInteger(noticeTime) && noticeTime < 5) {
                Integer postmanOverTime = orderInfo.getAgentPostmanOverTime();// 设置的要求骑手时长(postmanOverTime)
                if (null == postmanOverTime) {
                    postmanOverTime = 0;
                }
                Integer alertPostmanTime = orderInfo.getAlertPostmanTime();//  设置的骑手即将超时提醒时间[骑手接单-确认送达](alertPostmanTime)
                if (null == alertPostmanTime) {
                    alertPostmanTime = 0;
                }
//                noticeTime = postmanOverTime + alertPostmanTime + 20;
                noticeTime = postmanOverTime + alertPostmanTime;
                if (noticeTime <= 0) {
                    // 默认1小时
                    noticeTime = 60;
                } else {
                    noticeTime = noticeTime + 20;
                }
            }
            if (orderInfo.getZiQuTime() - nowTime <= noticeTime * 60 * 1000) {
                //推送给骑手
            } else {
                // 不到时间
                System.out.println(DateUtils.getCurrentDateTime() + "   自动派单--不到时间：" + orderNo + ":" + orderInfo.getZiQuTime());
//                return false;
                errSb.append("预约订单未到派单时间：" + orderNo + ",预约时间：" + orderInfo.getZiQuTime() + "\n");
                doLog(orderNo, errSb.toString());
                return new ResultInfo("预约订单未到派单时间");
            }
        }

        // 订单状态是否满足要求
        if ((ORDER_STATUS.SHOP_SURE == orderInfo.getOrderStatus() && 0 == orderInfo.getIsZiQu())
                || (ORDER_STATUS.PAYED == orderInfo.getOrderStatus() && (null != orderInfo.getOrderType() && (0 == ORDER_TYPE.PAO_TUI - orderInfo.getOrderType() || 0 == ORDER_TYPE.DAI_GOU - orderInfo.getOrderType() || 0 == ORDER_TYPE.BANG_BAN - orderInfo.getOrderType() || 0 == ORDER_TYPE.HUO_YUN - orderInfo.getOrderType())))
                || (0 == ORDER_STATUS.SUBMIT - orderInfo.getOrderStatus() && (null != orderInfo.getOrderType() && 0 == ORDER_TYPE.SERVICE_LOCK - orderInfo.getOrderType()))) {

        } else {
//            return true;
            System.out.println(DateUtils.getCurrentDateTime() + "    自动派单--订单状态不满足要求：" + orderNo + ":" + orderInfo.getOrderStatus());
            errSb.append("订单状态不满足要求：" + orderNo + ",当前状态：" + orderInfo.getOrderStatus() + "\n");
            doLog(orderNo, errSb.toString());
            return new ResultInfo();
        }

        // 订单经纬度是否符合要求
        if (ValidateUtil.isNotLatLng(orderInfo.getLat(), orderInfo.getLng())) {
//            return true;
            System.out.println(DateUtils.getCurrentDateTime() + "  自动派单--订单信息经纬度为空：" + orderInfo.getLat() + "," + orderInfo.getLng());
            errSb.append("订单信息经纬度为空：" + orderNo + "\n");
            doLog(orderNo, errSb.toString());
            return new ResultInfo();
        }
        Integer agentRang = null;
        List<String> pUserList = null;
        Long agentId = null;
        if (SYS_SETTINGS.POSTMAN_SERVICE_SHOP != null && SYS_SETTINGS.POSTMAN_SERVICE_SHOP == 1
                && ((orderInfo.getOrderType() - ORDER_TYPE.PAO_TUI == 0 && orderInfo.getIsShopPaoTuiOrder() != null && orderInfo.getIsShopPaoTuiOrder() == 1)
                || !ORDER_TYPE.PAOTUI_TYPE_LIST.contains(orderInfo.getOrderType()))) {
            ShopInfo shop = null;
            if (orderInfo.getOrderType() != null && orderInfo.getOrderType() - ORDER_TYPE.PAO_TUI == 0 && orderInfo.getIsShopPaoTuiOrder() != null && orderInfo.getIsShopPaoTuiOrder() == 1) {
                // 商家跑腿订单
                shop = ShopMemory.getInstance().getShopByUsername(orderInfo.getUsername());
            } else {
                shop = ShopMemory.getInstance().getShopById(orderInfo.getShopId());
            }
            if (shop == null) {
                System.out.println(DateUtils.getCurrentDateTime() + "  自动派单--店铺信息为空：" + orderInfo.getShopId());
                errSb.append("店铺信息为空：" + orderNo + "\n");
                doLog(orderNo, errSb.toString());
                return new ResultInfo();
            }
            pUserList = PostmanShopRelationMemory.getInstance().listShopPostManListByShopUsername(shop.getOwnUsername());
            if (!ValidateUtil.isAbsList(pUserList)) {
                // 商家没有骑手
//                System.out.println("当前商家没有骑手:" + orderInfo.getOrderNo() + "," + orderInfo.getShopId());
                errSb.append("当前商家没有骑手：" + orderNo + ",商圈id：" + orderInfo.getShopId() + "\n");
                doLog(orderNo, errSb.toString());
                return new ResultInfo("当前商家没有骑手");
            }
            agentRang = SYS_SETTINGS.DELIVERY_RANGE;
            if (ValidateUtil.isNotAbsInteger(agentRang)) {
                agentRang = 5;
            }
        } else {
            // 获取订单所属商圈
            agentId = orderInfo.getAgentId();
            if (ValidateUtil.isNotID(agentId)) {
                // todo 不是按商圈的，根据经纬度处理
                System.out.println(DateUtils.getCurrentDateTime() + "  自动派单--商圈id为空：" + orderNo);
//            return true;
                errSb.append("商圈id为空：" + orderNo + "\n");
                doLog(orderNo, errSb.toString());
                return new ResultInfo();
            }

            CityAgent agentInfo = CityAgentMemory.getInstance().getById(agentId);
            if (null == agentInfo) {
//            return true;
                System.out.println(DateUtils.getCurrentDateTime() + "  自动派单--商圈信息不存在：" + orderNo);
                errSb.append("商圈信息不存在：" + orderNo + ",商圈id：" + agentId + "\n");
                doLog(orderNo, errSb.toString());
                return new ResultInfo();
            }
            // 商圈最大距离
            agentRang = agentInfo.getRang();
            if (ValidateUtil.isNotAbsInteger(agentRang)) {
                agentRang = SYS_SETTINGS.DELIVERY_RANGE;
                if (ValidateUtil.isNotAbsInteger(agentRang)) {
                    agentRang = 5;
                }
            }
            // 获取该商圈所有骑手
            pUserList = PostmanAgentRelationMemory.getInstance().listOfAgentId(agentId);
            if (!ValidateUtil.isAbsList(pUserList)) {
                // 该商圈没有骑手
                System.out.println("该商圈没有骑手:" + orderInfo.getOrderNo() + "," + orderInfo.getAgentId());
//            return false;
                errSb.append("该商圈没有骑手：" + orderNo + ",商圈id：" + agentId + "\n");
                doLog(orderNo, errSb.toString());
                return new ResultInfo("该商圈没有骑手");
            }
        }

        // 符合条件骑手
        List<DispatchInfo> disList = new ArrayList<>();
        // 无符合条件骑手时的备用骑手
        List<DispatchInfo> usList = new ArrayList<>();
        // 遍历骑手
        for (int i = 0; i < pUserList.size(); i++) {
            String username = pUserList.get(i);
            if (ValidateUtil.isNull(username)) {
                continue;
            }

            // 获取骑手信息
            CityPostman postman = CityPostmanMemory.getInstance().getPostman(username);
            if (null == postman) {
                continue;
            }

            // 骑手的位置信息
            PostmanPositionInfo positionInfo = PostmanPositionMemory.getInstance().get(postman.getId());
            if (null == positionInfo) {
                System.out.println(DateUtils.getCurrentDateTime() + "  自动派单--骑手位置信息不存在：" + orderNo + "；username:" + username + ";postmanId:" + postman.getId());
                errSb.append(username + ",骑手位置信息不存在：" + orderNo + "\n");
                continue;
            }

            // 经纬度是否有效
            if (ValidateUtil.isNotLatLng(positionInfo.getLat(), positionInfo.getLng())) {
                System.out.println(DateUtils.getCurrentDateTime() + "  自动派单--骑手位置信息不完整：" + orderNo + "；username:" + username);
                errSb.append(username + ",骑手位置信息不完整：" + orderNo + "\n");
                continue;
            }

            // 验证骑手的基本信息
            ResultInfo resultInfo = isUsefulPostmanBase(postman, agentId, orderNo);
            if (null == resultInfo) {
                // 失败
                System.out.println(DateUtils.getCurrentDateTime() + "  自动派单--无效骑手：" + orderNo + "；username:" + username);
                errSb.append(username + ",无效骑手:" + orderNo);
                continue;
            } else {
                if (!resultInfo.isSuccess()) {
                    System.out.println(DateUtils.getCurrentDateTime() + "  自动派单--" + resultInfo.getError() + "：" + orderNo + "；username:" + username);
//                    errSb.append("---begin----" + username + ",无效骑手:" + orderNo + "-------\n");
                    errSb.append(resultInfo.getError() + "\n");
//                    errSb.append("---end----" + username + ",无效骑手:" + orderNo + "-------\n");
                    continue;
                }
            }

            DispatchInfo dispatchInfo = new DispatchInfo();
            // 骑手离订单的距离(米)
            double distance = Geohash.distance(positionInfo.getLat(), positionInfo.getLng(), orderInfo.getLat(), orderInfo.getLng());
            // 距离是否超出商圈范围
            if (JYMathDoubleUtils.sub(distance, agentRang * 1000) > 0) {
                System.out.println(DateUtils.getCurrentDateTime() + "  自动派单--距离超出商圈范围：" + orderNo + "；" + distance);
                errSb.append(username + ",距离骑手，超出范围：" + orderNo + ",实际距离：" + (JYMathDoubleUtils.div(distance, 1000, 2)) + ",商圈范围：" + agentRang + "\n");
                continue;
            }
            dispatchInfo.setPostmanInfo(postman);
            dispatchInfo.setDistance(distance);

            // 备用骑手
            usList.add(dispatchInfo);

            // 获取骑手进行中的一个订单
            List<OrderInfo> orderList = PostmanOrderMemoryMan.listOfPostmanIng(postman.getUsername(), 0l, 1);
            if (ValidateUtil.isAbsList(orderList)) {
                OrderInfo postmanOrder = orderList.get(0);
                if (null != postmanOrder && ValidateUtil.isLatLng(postmanOrder.getLat(), postmanOrder.getLng())) {
//                    // 获取骑手最后订单与新订单夹角
//                    double angle = AngleUtils.getSubAngle(positionInfo.getLat(), positionInfo.getLng(),
//                            postmanOrder.getLat(), postmanOrder.getLng(),
//                            orderInfo.getLat(), orderInfo.getLng());
//
//                    // todo 夹角大于45度
//                    if (angle > 45) {
////                        System.out.println("夹角大于45：" + orderNo + "," + angle);
//                        System.out.println(DateUtils.getCurrentDateTime() + "  自动派单--夹角大于45：" + orderNo + "；角度：" + angle + ";骑手：" + postman.getUsername());
//                        errSb.append(username + ",距离骑手，超出范围：" + orderNo + ",夹角大于45：" + angle + "\n");
//                        continue;
//                    }
//                    dispatchInfo.setAngle(angle);

                    if (null == shopRang || shopRang <= 0) {
                        shopRang = 1000l;
                    }
                    // 手里有单话，商家与商家之间的距离
                    if (ValidateUtil.isLatLng(orderInfo.getShopLat(), orderInfo.getShopLng())) {
                        // 商家与商家之间的距离(米)
                        double shopDis = Geohash.distance(orderInfo.getLat(), orderInfo.getLng(), orderInfo.getShopLat(), orderInfo.getShopLng());
                        if (shopRang - shopDis < 0) {
                            System.out.println(DateUtils.getCurrentDateTime() + "  自动派单--商家与商家距离超过" + shopRang + "米：" + orderNo + "；骑手：" + postman.getUsername());
                            errSb.append(username + ",商家与商家距离超过" + shopRang + "米：" + orderNo + ",距离：" + shopDis + "米\n");
                            continue;
                        }
                    } else {
                        System.out.println(DateUtils.getCurrentDateTime() + "  自动派单--商家与商家距离,商家经纬度为空：" + orderNo + "；骑手：" + postman.getUsername());
                        errSb.append(username + ",商家与商家距离，商家经纬度为空：" + orderNo + "\n");
                        continue;
                    }
                    // 手里有单话，用户与用户之间的距离
                    if (null == userRang || userRang <= 0) {
                        userRang = 2000l;
                    }
                    // 用户与用户之间的距离(米)
                    double userDis = Geohash.distance(orderInfo.getLat(), orderInfo.getLng(), postmanOrder.getLat(), postmanOrder.getLng());
                    if (userRang - userDis < 0) {
                        System.out.println(DateUtils.getCurrentDateTime() + "  自动派单--用户与用户之间的距离超过" + userRang + "米：" + orderNo + "；骑手：" + postman.getUsername());
                        errSb.append(username + ",用户与用户之间的距离超过" + userRang + "米：" + orderNo + ",距离：" + userDis + "米\n");
                        continue;
                    }

                    // 店1 用户1 用户2的夹角小于45
                    if (ValidateUtil.isLatLng(orderInfo.getShopLat(), orderInfo.getShopLng()) && ValidateUtil.isLatLng(orderInfo.getLat(), orderInfo.getLng())) {
                        double angle1 = AngleUtils.getSubAngle(postmanOrder.getShopLat(), postmanOrder.getShopLng(),
                                postmanOrder.getLat(), postmanOrder.getLng(),
                                orderInfo.getLat(), orderInfo.getLng());
                        if (angle1 > 45) {
                            System.out.println(DateUtils.getCurrentDateTime() + "  自动派单--店1 用户1 用户2,夹角大于45：" + orderNo + "；角度：" + angle1 + ";骑手：" + postman.getUsername());
                            errSb.append(postman.getUsername() + ",店1 用户1 用户2：" + orderNo + ",夹角大于45：" + angle1 + "\n");
                            continue;
                        }
                    } else {
                        System.out.println(DateUtils.getCurrentDateTime() + "  自动派单--店1 用户1 用户2,经纬度有问题：" + orderNo + "；骑手：" + postman.getUsername());
                        errSb.append(postman.getUsername() + "  自动派单--店1 用户1 用户2,经纬度有问题：" + orderNo + "；骑手：" + postman.getUsername() + "\n");
                        continue;
                    }

                    // 店1 店2 用户1的夹角小于45度
                    if (ValidateUtil.isLatLng(orderInfo.getShopLat(), orderInfo.getShopLng()) && ValidateUtil.isLatLng(postmanOrder.getShopLat(), postmanOrder.getShopLng())) {
                        double angle2 = AngleUtils.getSubAngle(postmanOrder.getShopLat(), postmanOrder.getShopLng(),
                                orderInfo.getShopLat(), orderInfo.getShopLng(),
                                postmanOrder.getLat(), postmanOrder.getLng());
                        if (angle2 > 45) {
                            System.out.println(DateUtils.getCurrentDateTime() + "  自动派单--店1 店2 用户1,夹角大于45：" + orderNo + "；角度：" + angle2 + ";骑手：" + postman.getUsername());
                            errSb.append(postman.getUsername() + ",店1 店2 用户1：" + orderNo + ",夹角大于45：" + angle2 + "\n");
                            continue;
                        }
                    } else {
                        System.out.println(DateUtils.getCurrentDateTime() + "  自动派单--店1 店2 用户1,经纬度有问题：" + orderNo + "；骑手：" + postman.getUsername());
                        errSb.append(postman.getUsername() + "  自动派单--店1 店2 用户1,经纬度有问题：" + orderNo + "；骑手：" + postman.getUsername() + "\n");
                        continue;
                    }

                }
            }


            disList.add(dispatchInfo);
        }

        if (!ValidateUtil.isAbsList(disList)) {
            // 无符合条件骑手，并且只有一个备用骑手时，直接派个备用骑手（因为有商圈只有一个骑手）
            if (ValidateUtil.isAbsList(usList) && usList.size() == 1) {
                if (null != usList.get(0) && null != usList.get(0).getPostmanInfo()) {
                    OrderMan.setOrderPostman(orderInfo.getOrderNo(), usList.get(0).getPostmanInfo(), opUsername);
//                    return true;
                    return new ResultInfo();
                }
            }
//            return false;
            System.out.println(DateUtils.getCurrentDateTime() + "  自动派单--没有可选择的骑手：" + orderNo + "\n");
            errSb.append("没有可选择的骑手：" + orderNo + "\n");
            doLog(orderNo, errSb.toString());
            return new ResultInfo("没有可选择的骑手" + "\n");
        }
        // 将骑手按距离最近的最前面排序
        JYListSort.sort(disList, "distance");

        // 骑手最多可接单数量
        int postmanMaxOrderCount = 10;
        boolean isAgentSettings = false;// 是否使用商圈的设置
        if (ValidateUtil.isID(agentId)) {
            OrderOverTimeInfo overTimeInfo = AgentOrderOverTimeMemory.getInstance().getAgentOrderOverTimeInfoByAgentId(agentId);
            if (null != overTimeInfo) {
                postmanMaxOrderCount = overTimeInfo.getPostmanMaxOrderNum();
                isAgentSettings = true;
            }
        }
        if (!isAgentSettings && null != SYS_SETTINGS.POSTMAN_MAX_ORDER_NUM && SYS_SETTINGS.POSTMAN_MAX_ORDER_NUM > 0) {
            postmanMaxOrderCount = SYS_SETTINGS.POSTMAN_MAX_ORDER_NUM;
        }

        // 遍历骑手列表
        for (int i = 0; i < disList.size(); i++) {
            DispatchInfo dispatchInfo = disList.get(i);
            if (null == dispatchInfo) {
                continue;
            }
            CityPostman postman = dispatchInfo.getPostmanInfo();
            if (null == postman) {
                continue;
            }
            if (ValidateUtil.isNull(postman.getUsername())) {
                continue;
            }
            // 获取骑手订单量
            Integer orderCount = PostmanOrderMemoryMan.getPostmanIngOrderCount(postman.getUsername());
            if (null == orderCount) {
                orderCount = 0;
            }
            if (0 == orderCount) {
                // 该骑手没有订单
                System.out.println(DateUtils.getCurrentDateTime() + "  自动派单--该骑手没有订单，派给他：" + orderNo + ",orderCount: " + orderCount + "\n");
                // 所需要的骑手
                OrderMan.setOrderPostman(orderInfo.getOrderNo(), postman, opUsername);
                // 结束
//                return true;
                return new ResultInfo();
            }

            disList.get(i).setOrderCount(orderCount);
        }

        // 遍历骑手列表
        for (int i = 0; i < disList.size(); i++) {
            DispatchInfo dispatchInfo = disList.get(i);
            if (null == dispatchInfo) {
                continue;
            }
            CityPostman postman = dispatchInfo.getPostmanInfo();
            if (null == postman) {
                continue;
            }
            if (ValidateUtil.isNull(postman.getUsername())) {
                continue;
            }
            // 获取骑手订单量
            Integer orderCount = dispatchInfo.getOrderCount();

            // 骑手可接单量
            if (postmanMaxOrderCount > 0 && orderCount >= postmanMaxOrderCount) {
                System.out.println("超出骑手可接单量：" + orderInfo.getOrderNo() + "," + postmanMaxOrderCount + "," + orderCount);
                errSb.append(postman.getUsername() + ",超出骑手可接单量：" + orderNo + ",可接单数量：" + postmanMaxOrderCount + ",实际数量" + orderCount + "\n");
                continue;
            } else {
                // 分配
                OrderMan.setOrderPostman(orderInfo.getOrderNo(), postman, opUsername);
//                return true;
                return new ResultInfo();
            }
        }

        // 无符合条件骑手，并且只有一个备用骑手时，直接派个备用骑手（因为有商圈只有一个骑手）
        if (ValidateUtil.isAbsList(usList) && usList.size() == 1) {
            System.out.println("有一个备用骑手：" + orderNo);
            if (null != usList.get(0) && null != usList.get(0).getPostmanInfo()) {
                OrderMan.setOrderPostman(orderInfo.getOrderNo(), usList.get(0).getPostmanInfo(), opUsername);
//                return true;
                return new ResultInfo();
            } else {
                System.out.println("一个备用骑手无效：" + orderNo);
                errSb.append("一个备用骑手无效：" + orderNo + "\n");
            }
        }

        System.out.println(DateUtils.getCurrentDateTime() + "  自动派单--没有可选择的骑手：" + orderNo);
        errSb.append("没有可选择的骑手：" + orderNo + "\n");
        doLog(orderNo, errSb.toString());
        return new ResultInfo("骑手都无效");
    }

    //---------------------------------------------

    private static ResultInfo isUsefulPostmanBase(CityPostman postman, Long agentId, String orderNo) {
        if (null == postman) {
            return new ResultInfo("骑手信息为空");
        }

        //0 锁定  1未锁定
        if (null != postman.getIsLock() && 0 == 1 - postman.getIsLock()) {
            System.out.println(DateUtils.getCurrentDateTime() + "  " + orderNo + " 已被锁定，无法接单," + postman.getUsername());
            return new ResultInfo(postman.getUsername() + ",已被锁定，无法接单:" + orderNo);
        }

        if (0 == POSTMAN_WORK_STATUS.POSTMAN_OFF_WORK - postman.getIsWork() || 0 == POSTMAN_WORK_STATUS.POSTMAN_BUSY - postman.getIsWork()) {
            // 未上班、或者忙碌的骑手不进行自动派单
            System.out.println(DateUtils.getCurrentDateTime() + "  " + orderNo + "  骑手已下班：" + postman.getUsername() + "," + postman.getIsWork());
            return new ResultInfo(postman.getUsername() + ",骑手已下班:" + orderNo);
        }

        if (null != SYS_SETTINGS.POSTMAN_MUST_VERIFY && 0 == 1 - SYS_SETTINGS.POSTMAN_MUST_VERIFY
                && (null == postman.getIsVerify() || 0 != 1 - postman.getIsVerify())) {
//            return AjaxResult.errorResult("您尚未通过认证，请先去认证");
            System.out.println(DateUtils.getCurrentDateTime() + "  " + orderNo + "  骑手未认证：" + postman.getUsername());
            return new ResultInfo(postman.getUsername() + ",骑手未认证:" + orderNo);
        }
        UserInfo user = UserInfoMemory.getInstance().getUserInfo(postman.getUsername());
        if (null == user) {
            System.out.println(DateUtils.getCurrentDateTime() + "  " + orderNo + "  骑手在用户信息中不存在:" + postman.getUsername());
            return new ResultInfo(postman.getUsername() + ",骑手在用户信息中不存在:" + orderNo);
        }
        if (null != SYS_SETTINGS.POSTMAN_MUST_VERIFY_FACE && 0 == 1 - SYS_SETTINGS.POSTMAN_MUST_VERIFY_FACE) {
            if (null != user.getIsCert() && 0 == 1 - user.getIsCert()) {
                //已认证
            } else {
                System.out.println(DateUtils.getCurrentDateTime() + "  " + orderNo + "  自动派单--骑手未实名认证：" + postman.getUsername());
//                return AjaxResult.errorResult("未通过实名认证，请先去认证");
                return new ResultInfo(postman.getUsername() + ",骑手未实名认证:" + orderNo);
            }
        }


        // 配送员可抢单数量
        boolean isAgentSettings = false;// 是否使用商圈的设置
        Integer postmanCanGrabOrder = -1;// 配送员可抢单数量
        // 服务商家那种
        if (SYS_SETTINGS.POSTMAN_SERVICE_SHOP == null || SYS_SETTINGS.POSTMAN_SERVICE_SHOP != 1) {
            if (ValidateUtil.isID(agentId)) {
                OrderOverTimeInfo overTimeInfo = AgentOrderOverTimeMemory.getInstance().getAgentOrderOverTimeInfoByAgentId(agentId);
                if (null != overTimeInfo) {
                    postmanCanGrabOrder = overTimeInfo.getPostmanCanGrabOrder();
                    isAgentSettings = true;
                }
            }
        }
        if ((isAgentSettings && postmanCanGrabOrder > 0) || (!isAgentSettings && null != SYS_SETTINGS.POSTMAN_CAM_GRAB_ORDER && SYS_SETTINGS.POSTMAN_CAM_GRAB_ORDER > 0)) {
            int count = PostmanOrderMemoryMan.getPostmanIngOrderCount(user.getUsername());
            if (isAgentSettings) {
                if (count - postmanCanGrabOrder >= 0) {
//                return AjaxResult.errorResult("您有未完成订单，无法继续抢单");
                    System.out.println(DateUtils.getCurrentDateTime() + "  自动派单--有未完成订单，无法继续派单：" + orderNo + ";" + postman.getUsername() + ";count:" + count + ";postmanCanGrabOrder:" + postmanCanGrabOrder);
                    return new ResultInfo(postman.getUsername() + ",有未完成订单，无法继续派单:" + orderNo + ";配送中:" + count + ";骑手可抢单:" + postmanCanGrabOrder);
                }
            } else {
                if (count - SYS_SETTINGS.POSTMAN_CAM_GRAB_ORDER >= 0) {
//                return AjaxResult.errorResult("您有未完成订单，无法继续抢单");
                    System.out.println(DateUtils.getCurrentDateTime() + "  自动派单--有未完成订单，无法继续派单2：" + orderNo + ";" + postman.getUsername() + ";count:" + count + ";postmanCanGrabOrder:" + SYS_SETTINGS.POSTMAN_CAM_GRAB_ORDER);
                    return new ResultInfo(postman.getUsername() + ",有未完成订单，无法继续派单2:" + orderNo + ";配送中:" + count + ";骑手可抢单:" + postmanCanGrabOrder);
                }
            }
        }

//        if (null != SYS_SETTINGS.POSTMAN_CAM_GRAB_ORDER && SYS_SETTINGS.POSTMAN_CAM_GRAB_ORDER > 0) {
//            int count = OrderInfoMemory.getInstance().getPostmanIngOrderCount(user.getUsername());
//            if (count - SYS_SETTINGS.POSTMAN_CAM_GRAB_ORDER >= 0) {
////                return AjaxResult.errorResult("您有未完成订单，无法继续抢单");
//                return false;
//            }
//        }

        if (null != SYS_SETTINGS.POSTMAN_MUST_DEPOSIT && 0 == 1 - SYS_SETTINGS.POSTMAN_MUST_DEPOSIT) {
            // 必须缴纳
            //验证押金金额是否满足
            UserWallet userWallet = UserWalletMemory.getInstance().getWallet(user.getUsername());
            if (null == userWallet) {
//                return AjaxResult.errorResult("您还未缴纳押金，请先缴纳押金");
                System.out.println(DateUtils.getCurrentDateTime() + "  自动派单--未缴纳押金：" + postman.getUsername() + ";orderno:" + orderNo);
                return new ResultInfo(postman.getUsername() + ",骑手未缴纳押金:" + orderNo);
            }
            if (null == userWallet.getDepositMoney() || userWallet.getDepositMoney() <= 0) {
//                return AjaxResult.errorResult("您还未缴纳押金，请先缴纳押金！");
                System.out.println(DateUtils.getCurrentDateTime() + "  自动派单--未缴纳押金2：" + postman.getUsername() + ";orderno:" + orderNo);
                return new ResultInfo(postman.getUsername() + ",未缴纳押金2:" + orderNo);
            }
            //必须缴纳的押金金额
            Double money = SysConfigDepositMemory.getInstance().getByType(UserType.POSTMAN);
            if (null == money) {
                money = 0d;
            }

            if (JYMathDoubleUtils.sub(userWallet.getDepositMoney(), money) < 0) {
//                return AjaxResult.errorResult("您缴纳的押金不足，请先缴纳押金");
                System.out.println(DateUtils.getCurrentDateTime() + "  自动派单--押金不足：" + postman.getUsername() + ";orderno:" + orderNo);
                return new ResultInfo(postman.getUsername() + ",押金不足:" + orderNo);
            }
        }


        return new ResultInfo();
    }


    private static ResultInfo dispatchServerV4(String orderNo,
                                               Long shopRang,// 骑手 手里有单话，商家与商家之间的距离
                                               String opUsername) {

        StringBuffer errSb = new StringBuffer();

        OrderInfo orderInfo = OrderInfoMemory.getInstance().getOrderInfo(orderNo);
        if (null == orderInfo) {
//            return true;
            System.out.println(DateUtils.getCurrentDateTime() + "  自动派单--订单信息不存在：" + orderNo);
            errSb.append("订单信息不存在:" + orderNo);
            doLog(orderNo, errSb.toString());
            return new ResultInfo();
        }

        // 重复派单问题
        if (ValidateUtil.isNotNull(orderInfo.getPostManUsername())) {
            // 已有骑手不再派单
            System.out.println(DateUtils.getCurrentDateTime() + "  自动派单--已存在骑手：" + orderNo + ",postman:" + orderInfo.getPostManUsername());
            return new ResultInfo();
        }

        // 只派 配送单
        if (0 != orderInfo.getIsZiQu() - ZI_QU_TYPE.PEI_SONG) {
            return new ResultInfo();
        }

        // 订单状态是否满足要求
        if ((ORDER_STATUS.SHOP_SURE == orderInfo.getOrderStatus() && 0 == orderInfo.getIsZiQu())
                || (ORDER_STATUS.PAYED == orderInfo.getOrderStatus() && (null != orderInfo.getOrderType() && (0 == ORDER_TYPE.PAO_TUI - orderInfo.getOrderType() || 0 == ORDER_TYPE.DAI_GOU - orderInfo.getOrderType() || 0 == ORDER_TYPE.BANG_BAN - orderInfo.getOrderType() || 0 == ORDER_TYPE.HUO_YUN - orderInfo.getOrderType())))
                || (0 == ORDER_STATUS.SUBMIT - orderInfo.getOrderStatus() && (null != orderInfo.getOrderType() && 0 == ORDER_TYPE.SERVICE_LOCK - orderInfo.getOrderType()))) {

        } else {
            System.out.println(DateUtils.getCurrentDateTime() + "    自动派单--订单状态不满足要求：" + orderNo + ":" + orderInfo.getOrderStatus());
            errSb.append("订单状态不满足要求：" + orderNo + ",当前状态：" + orderInfo.getOrderStatus() + "\n");
            doLog(orderNo, errSb.toString());
            return new ResultInfo();
        }

        // 订单经纬度是否符合要求
        if (ValidateUtil.isNotLatLng(orderInfo.getLat(), orderInfo.getLng())) {
            System.out.println(DateUtils.getCurrentDateTime() + "  自动派单--订单信息经纬度为空：" + orderInfo.getLat() + "," + orderInfo.getLng());
            errSb.append("订单信息经纬度为空：" + orderNo + "\n");
            doLog(orderNo, errSb.toString());
            return new ResultInfo();
        }
        List<String> pUserList = null;
        Long agentId = null;

        ShopInfo shop = ShopMemory.getInstance().getShopByUsername(orderInfo.getUsername());
        if (shop == null) {
            shop = ShopMemory.getInstance().getShopById(orderInfo.getShopId());
        }
        if (shop == null) {
            System.out.println(DateUtils.getCurrentDateTime() + "  自动派单--店铺信息为空：" + orderInfo.getShopId());
            errSb.append("店铺信息为空：" + orderNo + "\n");
            doLog(orderNo, errSb.toString());
            return new ResultInfo();
        }
        pUserList = PostmanShopRelationMemory.getInstance().listShopPostManListByShopUsername(shop.getOwnUsername());
        if (!ValidateUtil.isAbsList(pUserList)) {
            // 商家没有骑手
            errSb.append("当前商家没有骑手：" + orderNo + ",商圈id：" + orderInfo.getShopId() + "\n");
            doLog(orderNo, errSb.toString());
            return new ResultInfo("当前商家没有骑手");
        }

        // 符合条件骑手
        List<DispatchInfo> disList = new ArrayList<>();
        // 遍历骑手
        for (int i = 0; i < pUserList.size(); i++) {
            String username = pUserList.get(i);
            if (ValidateUtil.isNull(username)) {
                continue;
            }

            // 获取骑手信息
            CityPostman postman = CityPostmanMemory.getInstance().getPostman(username);
            if (null == postman) {
                continue;
            }

            //必须是上班状态
            if (postman.getIsWork() != 1) {
                continue;
            }
            //第一轮为驻店骑手
            if (postman.getPostman_type() != null && postman.getPostman_type() != 1) {
                continue;
            }

            // 骑手的位置信息
            PostmanPositionInfo positionInfo = PostmanPositionMemory.getInstance().get(postman.getId());
            if (null == positionInfo) {
                System.out.println(DateUtils.getCurrentDateTime() + "  自动派单--骑手位置信息不存在：" + orderNo + "；username:" + username + ";postmanId:" + postman.getId());
                errSb.append(username + ",骑手位置信息不存在：" + orderNo + "\n");
                continue;
            }

            // 经纬度是否有效
            if (ValidateUtil.isNotLatLng(positionInfo.getLat(), positionInfo.getLng())) {
                System.out.println(DateUtils.getCurrentDateTime() + "  自动派单--骑手位置信息不完整：" + orderNo + "；username:" + username);
                errSb.append(username + ",骑手位置信息不完整：" + orderNo + "\n");
                continue;
            }

            // 验证骑手的基本信息
            ResultInfo resultInfo = isUsefulPostmanBase(postman, agentId, orderNo);
            if (null == resultInfo) {
                // 失败
                System.out.println(DateUtils.getCurrentDateTime() + "  自动派单--无效骑手：" + orderNo + "；username:" + username);
                errSb.append(username + ",无效骑手:" + orderNo);
                continue;
            } else {
                if (!resultInfo.isSuccess()) {
                    System.out.println(DateUtils.getCurrentDateTime() + "  自动派单--" + resultInfo.getError() + "：" + orderNo + "；username:" + username);
                    errSb.append(resultInfo.getError() + "\n");
                    continue;
                }
            }

            DispatchInfo dispatchInfo = new DispatchInfo();
            // 骑手离订单的距离(米)
            double distance = 0;
            if (ValidateUtil.isLatLng(orderInfo.getShopLat(), orderInfo.getShopLng())) {
                distance = Geohash.distance(positionInfo.getLat(), positionInfo.getLng(), orderInfo.getShopLat(), orderInfo.getShopLng());
            } else {
                distance = Geohash.distance(positionInfo.getLat(), positionInfo.getLng(), orderInfo.getLat(), orderInfo.getLng());
            }

            int orderCount = PostmanOrderMemoryMan.getPostmanIngOrderCount(postman.getUsername());

            dispatchInfo.setPostmanInfo(postman);
            dispatchInfo.setDistance(distance);
            dispatchInfo.setOrderCount(orderCount);
            disList.add(dispatchInfo);
        }

        // 将骑手按距离最近的最前面排序
        JYListSort.sort(disList, "distance");


        // 遍历每个骑手的待取货订单，按要求送达时间最早的排序
        for (int t = 0; t < disList.size(); t++) {
            DispatchInfo dispatchInfo = disList.get(t);
            CityPostman postman = dispatchInfo.getPostmanInfo();
            log.info("=========postmanId=========="+postman.getId());
            List<OrderInfo> orderList = PostmanOrderMemoryMan.listOfPostmanGrab(postman.getUsername(), 0l, 0, 0);
            // TODO 遍历获取的所有骑手有没有订单（待取货 + 配送中）
            if (orderList == null || orderList.size() == 0) {
                // 分配
                log.info("============orderInfo========="+orderInfo);
                log.info("============postman========="+postman);
                log.info("============opUsername======"+opUsername);
                OrderMan.setOrderPostman(orderInfo.getOrderNo(), postman, opUsername);
                return new ResultInfo();
            }
            orderList.sort((o1, o2) -> {
                long o1Time = 0;
                long o1PeakTime = 0;
                long o2Time = 0;
                long o2PeakTime = 0;
                // 判断是预约单还是立即配送
                if(o1.getZiQuTime()!=null && o1.getZiQuTime()!=0){
                    // 预约单
                    o1Time = o1.getZiQuTime();
                }else{
                    // 立即配送
                    int agentPostmanOverTime1 = o1.getAgentPostmanOverTime();
                    long createTime1 = o1.getCreateTime();
                    // 高峰用时时间
                    ShopInfo shop1 = ShopMemory.getInstance().getShopByUsername(o1.getUsername());
                    String peakHour1 = shop1.getPeakHour();
                    String peakTimeBucket1 = shop1.getPeakTimeBucket();
                    if(StringUtils.isNotEmpty(peakTimeBucket1)){
                        JSONArray jsonArray = JSONObject.parseArray(peakTimeBucket1);
                        SimpleDateFormat df = new SimpleDateFormat("HH:mm");
                        String now = df.format(new Date());
                        for (int i1 = 0; i1 < jsonArray.size(); i1++) {
                            JSONArray array = jsonArray.getJSONArray(i1);
                            if (DateUtils.isInTimeScope(now, array.getString(0), array.getString(1))) {
                                o1PeakTime = Integer.parseInt(StringUtils.isEmpty(peakHour1) ? "0" : peakHour1);
                            }
                        }
                    }
                    o1Time = createTime1 + (agentPostmanOverTime1 * 60 * 1000) + o1PeakTime;
                }

                if(o2.getZiQuTime()!=null && o2.getZiQuTime()!=0){
                    // 预约单
                    o2Time = o2.getZiQuTime();
                }else {
                    // 立即配送
                    int agentPostmanOverTime1 = o2.getAgentPostmanOverTime();
                    long createTime2 = o2.getCreateTime();
                    // 高峰用时时间
                    ShopInfo shop2 = ShopMemory.getInstance().getShopByUsername(o1.getUsername());
                    String peakHour2 = shop2.getPeakHour();
                    String peakTimeBucket2 = shop2.getPeakTimeBucket();
                    if(StringUtils.isNotEmpty(peakTimeBucket2)){
                        JSONArray jsonArray = JSONObject.parseArray(peakTimeBucket2);
                        SimpleDateFormat df = new SimpleDateFormat("HH:mm");
                        String now = df.format(new Date());
                        for (int i2 = 0; i2 < jsonArray.size(); i2++) {
                            JSONArray array = jsonArray.getJSONArray(i2);
                            if (DateUtils.isInTimeScope(now, array.getString(0), array.getString(1))) {
                                o2PeakTime = Integer.parseInt(StringUtils.isEmpty(peakHour2) ? "0" : peakHour2);
                            }
                        }
                    }
                    o2Time = createTime2 + (agentPostmanOverTime1 * 60 * 1000) + o2PeakTime;
                }
                return (int) (o1Time - o2Time);
            });
            // 排序中最早的订单
            OrderInfo oi = orderList.get(0);

            // 计算骑手待取货里要求时间最早的订单的实际
            long agentPostmanOverTime = oi.getCreateTime() + (oi.getAgentPostmanOverTime() * 60 * 1000);
            dispatchInfo.setAgentPostmanOverTime(agentPostmanOverTime);
        }

        // 按骑手待取货里要求时间最早的订单排序
        JYListSort.sort(disList, "agentPostmanOverTime");

        // 骑手最多可接单数量
        int postmanMaxOrderCount;
        if (StringUtils.isNotEmpty(shop.getPostmanMaxOrder())) {
            postmanMaxOrderCount = Integer.parseInt(shop.getPostmanMaxOrder());
        } else {
            postmanMaxOrderCount = SYS_SETTINGS.POSTMAN_MAX_ORDER_NUM;
        }

        //TODO 2021/06/18
        // 按顺路订单逻辑，判断待指派订单是不是和上一步获取到的订单顺路
        log.info("==========顺路单逻辑开始==========");
        for (int p = 0; p < disList.size(); p++) {
            CityPostman postman = disList.get(p).getPostmanInfo();
            log.info("==========骑手ID:"+postman.getId()+"，顺路单逻辑开始==========");
            int postmanCount = disList.get(p).getOrderCount();
            List<OrderInfo> orderList = PostmanOrderMemoryMan.listOfPostmanGrab(postman.getUsername(), 0l, 0, 0);
            // 最早订单
            orderList.sort((o1, o2) -> {
                long o1Time = 0;
                long o1PeakTime = 0;
                long o2Time = 0;
                long o2PeakTime = 0;
                // 判断是预约单还是立即配送
                if(o1.getZiQuTime()!=null && o1.getZiQuTime()!=0){
                    // 预约单
                    o1Time = o1.getZiQuTime();
                }else{
                    // 立即配送
                    int agentPostmanOverTime1 = o1.getAgentPostmanOverTime();
                    long createTime1 = o1.getCreateTime();
                    // 高峰用时时间
                    ShopInfo shop1 = ShopMemory.getInstance().getShopByUsername(o1.getUsername());
                    String peakHour1 = shop1.getPeakHour();
                    String peakTimeBucket1 = shop1.getPeakTimeBucket();
                    if(StringUtils.isNotEmpty(peakTimeBucket1)){
                        JSONArray jsonArray = JSONObject.parseArray(peakTimeBucket1);
                        SimpleDateFormat df = new SimpleDateFormat("HH:mm");
                        String now = df.format(new Date());
                        for (int i1 = 0; i1 < jsonArray.size(); i1++) {
                            JSONArray array = jsonArray.getJSONArray(i1);
                            if (DateUtils.isInTimeScope(now, array.getString(0), array.getString(1))) {
                                o1PeakTime = Integer.parseInt(StringUtils.isEmpty(peakHour1) ? "0" : peakHour1);
                            }
                        }
                    }
                    o1Time = createTime1 + (agentPostmanOverTime1 * 60 * 1000) + o1PeakTime;
                }

                if(o2.getZiQuTime()!=null && o2.getZiQuTime()!=0){
                    // 预约单
                    o2Time = o2.getZiQuTime();
                }else {
                    // 立即配送
                    int agentPostmanOverTime1 = o2.getAgentPostmanOverTime();
                    long createTime2 = o2.getCreateTime();
                    // 高峰用时时间
                    ShopInfo shop2 = ShopMemory.getInstance().getShopByUsername(o1.getUsername());
                    String peakHour2 = shop2.getPeakHour();
                    String peakTimeBucket2 = shop2.getPeakTimeBucket();
                    if(StringUtils.isNotEmpty(peakTimeBucket2)){
                        JSONArray jsonArray = JSONObject.parseArray(peakTimeBucket2);
                        SimpleDateFormat df = new SimpleDateFormat("HH:mm");
                        String now = df.format(new Date());
                        for (int i2 = 0; i2 < jsonArray.size(); i2++) {
                            JSONArray array = jsonArray.getJSONArray(i2);
                            if (DateUtils.isInTimeScope(now, array.getString(0), array.getString(1))) {
                                o2PeakTime = Integer.parseInt(StringUtils.isEmpty(peakHour2) ? "0" : peakHour2);
                            }
                        }
                    }
                    o2Time = createTime2 + (agentPostmanOverTime1 * 60 * 1000) + o2PeakTime;
                }
                return (int) (o1Time - o2Time);
            });
            //新订单要与要与待取货订单夹角
            log.info("骑手id为:"+postman.getId()+"，待分配的订单的门店地址坐标为【"+orderInfo.getShopLng()+","+orderInfo.getShopLat()+"】");
            log.info("骑手id为:"+postman.getId()+"，最早订单的收货地址坐标为【"+orderList.get(0).getLng()+","+orderList.get(0).getLat()+"】");
            log.info("骑手id为:"+postman.getId()+"，待分配的订单的收货地址坐标为【"+orderInfo.getLng()+","+orderInfo.getLat()+"】");
            double angle = AngleUtils.getDegree(orderInfo.getShopLng(), orderInfo.getShopLat(), orderList.get(0).getLng(), orderList.get(0).getLat(), orderInfo.getLng(), orderInfo.getLat());
            log.info("骑手id为:"+postman.getId()+"，计算的夹角为："+angle);
            //新订单要与待取货订单夹角小于15度且圆心到点的距离小于半径
            double distance = Geohash.distance(orderInfo.getShopLng(), orderInfo.getShopLat(), orderInfo.getLng(), orderInfo.getLat());
            double radius = Geohash.distance(orderInfo.getShopLng(), orderInfo.getShopLat(), orderList.get(0).getLng(), orderList.get(0).getLat());
            //判断骑手是否达到了最大背单数且夹角小于15°且点在扇形面积内
            if (angle < 15 && distance < radius && postmanCount < postmanMaxOrderCount) {
                // 指派
                OrderMan.setOrderPostman(orderInfo.getOrderNo(), postman, opUsername);
                return new ResultInfo();
            }
            log.info("==========骑手ID:"+postman.getId()+"，顺路单逻辑结束==========");
        }
        log.info("==========顺路单逻辑结束==========");

        log.info("==========开始计算距离=========");

        log.info("==========排序前骑手的顺序=========");
        disList.forEach(System.out::println);

        //TODO 2021/06/11
        // 新增 计算每个骑手当前位置到最近收货地址的直线距离 +
        // 最近收货地址到下一个最近收货地址直线距离 + …… + 最后一个订单收货地址到门店的距离，将结果按最小值排序
        JYListSort.sortDistance(disList);

        log.info("==========排序后骑手的顺序=========");
        disList.forEach(System.out::println);

        // 遍历上一步得到的骑手，判断骑手是否达到了最大背单数
        log.info("==========开始判断背单数===========");
        for (int i = 0; i < disList.size(); i++) {
            DispatchInfo dispatchInfo = disList.get(i);
            if (null == dispatchInfo) {
                continue;
            }
            CityPostman postman = dispatchInfo.getPostmanInfo();
            if (null == postman) {
                continue;
            }
            if (ValidateUtil.isNull(postman.getUsername())) {
                continue;
            }
            // 获取骑手订单量
            Integer orderCount = PostmanOrderMemoryMan.getPostmanIngOrderCount(postman.getUsername());
            log.info("骑手ID:"+postman.getId()+"，身上订单数:"+orderCount);
            log.info("骑手ID:"+postman.getId()+"，门店要求最大数量:"+postmanMaxOrderCount);

            // 骑手可接单量
            if (postmanMaxOrderCount > 0 && orderCount >= postmanMaxOrderCount) {
                System.out.println("超出骑手可接单量：" + orderInfo.getOrderNo() + "," + postmanMaxOrderCount + "," + orderCount);
                errSb.append(postman.getUsername() + ",超出骑手可接单量：" + orderNo + ",可接单数量：" + postmanMaxOrderCount + ",实际数量" + orderCount + "\n");
                continue;
            } else {
                // 分配
                OrderMan.setOrderPostman(orderInfo.getOrderNo(), postman, opUsername);
                return new ResultInfo();
            }
        }

        // ===========================================================================

        // TODO 当驻店骑手流程完毕后，走蜂窝机动骑手逻辑
        List<CityPostman> cityPostmanList = HoneycombMemory.getInstance().getShopHoneycomb(orderInfo);
        log.info("自动派单---开始驻店骑手流程已走完，现在走蜂窝机动骑手指派流程");
        log.info("获取到订单门店所属蜂窝的骑手数量：" + cityPostmanList.size() + "(个)");


        // 符合条件的机动骑手
        List<DispatchInfo> honeycombAngleQualifiedList = new ArrayList<>();

        // TODO 订单门店蜂窝内也没有等待下一轮30秒
        if (!ValidateUtil.isAbsList(cityPostmanList)) {
            log.info("订单门店蜂窝内也没有等待下一轮指派");
            return new ResultInfo("订单门店蜂窝内也没有等待下一轮指派");
        }

        // 获取机动骑手距离门店的距离使其按最小值排序
        HoneycombMemory.getInstance().getPostmanDistanceOrderBy(cityPostmanList, orderInfo.getLng(), orderInfo.getLat());

        // 遍历蜂窝机动骑手列表
        for (int i = 0; i < cityPostmanList.size(); i++) {
            CityPostman postman = cityPostmanList.get(i);
            PostmanPositionInfo positionInfo = PostmanPositionMemory.getInstance().get(postman.getId());
            //没有位置信息的直接跳过
            if(positionInfo == null){
                continue;
            }
            // 获取骑手订单量
            DispatchInfo dispatchInfo = new DispatchInfo();
            // 骑手离订单的距离(米)
            double distance = 0;
            if (ValidateUtil.isLatLng(orderInfo.getShopLat(), orderInfo.getShopLng())) {
                distance = Geohash.distance(positionInfo.getLat(), positionInfo.getLng(), orderInfo.getShopLat(), orderInfo.getShopLng());
            } else {
                distance = Geohash.distance(positionInfo.getLat(), positionInfo.getLng(), orderInfo.getLat(), orderInfo.getLng());
            }
            if (ValidateUtil.isNull(postman.getUsername())) {
                continue;
            }
            // 获取骑手待抢订单
            List<OrderInfo> orderList = PostmanOrderMemoryMan.listOfPostmanIng(postman.getUsername(), 0l, 1);
            // 该骑手没有待抢订单直接指派
            if (!ValidateUtil.isAbsList(orderList)) {
                // 分配
                OrderMan.setOrderPostman(orderInfo.getOrderNo(), postman, opUsername);
                return new ResultInfo();
            }
            // 按要求送达时间最早进行排序
            orderList.sort((o1, o2) -> {
                long o1Time = 0;
                long o1PeakTime = 0;
                long o2Time = 0;
                long o2PeakTime = 0;
                // 判断是预约单还是立即配送
                if(o1.getZiQuTime()!=null && o1.getZiQuTime()!=0){
                    // 预约单
                    o1Time = o1.getZiQuTime();
                }else{
                    // 立即配送
                    int agentPostmanOverTime1 = o1.getAgentPostmanOverTime();
                    long createTime1 = o1.getCreateTime();
                    // 高峰用时时间
                    ShopInfo shop1 = ShopMemory.getInstance().getShopByUsername(o1.getUsername());
                    String peakHour1 = shop1.getPeakHour();
                    String peakTimeBucket1 = shop1.getPeakTimeBucket();
                    if(StringUtils.isNotEmpty(peakTimeBucket1)){
                        JSONArray jsonArray = JSONObject.parseArray(peakTimeBucket1);
                        SimpleDateFormat df = new SimpleDateFormat("HH:mm");
                        String now = df.format(new Date());
                        for (int i1 = 0; i1 < jsonArray.size(); i1++) {
                            JSONArray array = jsonArray.getJSONArray(i1);
                            if (DateUtils.isInTimeScope(now, array.getString(0), array.getString(1))) {
                                o1PeakTime = Integer.parseInt(StringUtils.isEmpty(peakHour1) ? "0" : peakHour1);
                            }
                        }
                    }
                    o1Time = createTime1 + (agentPostmanOverTime1 * 60 * 1000) + o1PeakTime;
                }

                if(o2.getZiQuTime()!=null && o2.getZiQuTime()!=0){
                    // 预约单
                    o2Time = o2.getZiQuTime();
                }else {
                    // 立即配送
                    int agentPostmanOverTime1 = o2.getAgentPostmanOverTime();
                    long createTime2 = o2.getCreateTime();
                    // 高峰用时时间
                    ShopInfo shop2 = ShopMemory.getInstance().getShopByUsername(o1.getUsername());
                    String peakHour2 = shop2.getPeakHour();
                    String peakTimeBucket2 = shop2.getPeakTimeBucket();
                    if(StringUtils.isNotEmpty(peakTimeBucket2)){
                        JSONArray jsonArray = JSONObject.parseArray(peakTimeBucket2);
                        SimpleDateFormat df = new SimpleDateFormat("HH:mm");
                        String now = df.format(new Date());
                        for (int i2 = 0; i2 < jsonArray.size(); i2++) {
                            JSONArray array = jsonArray.getJSONArray(i2);
                            if (DateUtils.isInTimeScope(now, array.getString(0), array.getString(1))) {
                                o2PeakTime = Integer.parseInt(StringUtils.isEmpty(peakHour2) ? "0" : peakHour2);
                            }
                        }
                    }
                    o2Time = createTime2 + (agentPostmanOverTime1 * 60 * 1000) + o2PeakTime;
                }
                return (int) (o1Time - o2Time);
            });
            // 获取最早送达时间的订单
            OrderInfo postmanOrder = orderList.get(0);
            if (null != postmanOrder && ValidateUtil.isLatLng(postmanOrder.getLat(), postmanOrder.getLng())) {
                // 获取骑手最早订单与新订单夹角
                double angle = AngleUtils.getDegree(positionInfo.getLng(),positionInfo.getLat(),
                        postmanOrder.getLng(),postmanOrder.getLat(),
                        orderInfo.getLng(),orderInfo.getLat());
                log.info("最早订单号为"+postmanOrder.getOrderNo()+"它于待指派的新订单的夹角为："+ angle);

                //最早订单
                double d1 = Geohash.distance(postmanOrder.getShopLat(), postmanOrder.getShopLng(), positionInfo.getLat(), positionInfo.getLng());
                log.info("最早订单号:"+postmanOrder.getOrderNo()+" 到骑手的距离为"+d1);

                //待指派订单
                double d2 = Geohash.distance(orderInfo.getLat(), orderInfo.getLng(), positionInfo.getLat(), positionInfo.getLng());
                log.info("待指派订单订单号:"+orderInfo.getOrderNo()+" 到骑手的距离为"+d2);

                // todo 夹角大于45度
                if (angle > 45) {
                    System.out.println(DateUtils.getCurrentDateTime() + "  自动派单--夹角大于45：" + orderNo + "；角度：" + angle + ";骑手：" + postman.getUsername());
                    errSb.append(postman.getUsername() + ",距离骑手，超出范围：" + orderNo + ",夹角大于45：" + angle + "\n");
                    continue;
                }
                if (d1 >= d2) {
                    log.info("新收货地址距离必须小于最早订单距离的骑手");
                    continue;
                }
                dispatchInfo.setPostmanInfo(postman);
                dispatchInfo.setDistance(distance);
                honeycombAngleQualifiedList.add(dispatchInfo);
            }
        }

        // 机动骑手也没有结果则重新开始计算
        if (!ValidateUtil.isAbsList(honeycombAngleQualifiedList)) {
            return new ResultInfo("没有符合计算结果的骑手，等待下一轮重新计算");
        }

        // 将骑手按距离最近的最前面排序
        JYListSort.sort(honeycombAngleQualifiedList, "distance");

        // 遍历上一步得到的骑手，判断骑手是否达到了最大背单数
        for (int u = 0; u < honeycombAngleQualifiedList.size(); u++) {
            CityPostman postman = honeycombAngleQualifiedList.get(u).getPostmanInfo();
            DispatchInfo dispatchInfoHoneycomb = honeycombAngleQualifiedList.get(u);
            CityPostman postmanHoneycombInfo = dispatchInfoHoneycomb.getPostmanInfo();
            if (null == postmanHoneycombInfo) {
                continue;
            }
            if (ValidateUtil.isNull(postmanHoneycombInfo.getUsername())) {
                continue;
            }
            // 获取骑手订单量
            Integer orderCount = PostmanOrderMemoryMan.getPostmanIngOrderCount(postman.getUsername());

            // 骑手可接单量
            if (postmanMaxOrderCount > 0 && orderCount >= postmanMaxOrderCount) {
                System.out.println("超出骑手可接单量：" + orderInfo.getOrderNo() + "," + postmanMaxOrderCount + "," + orderCount);
                errSb.append(postman.getUsername() + ",超出骑手可接单量：" + orderNo + ",可接单数量：" + postmanMaxOrderCount + ",实际数量" + orderCount + "\n");
                continue;
            } else {
                // 分配
                OrderMan.setOrderPostman(orderInfo.getOrderNo(), postman, opUsername);
                return new ResultInfo();
            }
        }

        System.out.println(DateUtils.getCurrentDateTime() + "自动派单--没有可选择的骑手：" + orderNo);
        errSb.append("没有可选择的骑手：" + orderNo + "\n");

        doLog(orderNo, errSb.toString());
        return new ResultInfo("骑手都无效");

    }


    // 处理自动派单日志
    private static void doLog(String orderNo, String log) {
        // 更新mongoDB数据库
        BasicDBObject query = new BasicDBObject();
        query.append("orderNo", orderNo);

        BasicDBObject update = new BasicDBObject();
        update.append("orderNo", orderNo);
        update.append("log", log);
        update.append("createTim", DateUtils.getCurrTime());
//        MongoDaoImpl.getInstance().update(ReleaseInformationMongo.onlineLogMongoDB, PojoTables.MG_DISPATCH_LOG, query, update, true);
    }
}
